我正在嘗試提高我在 Go 中實現的下載器的性能。我認為我遇到了內存使用問題,因為當我嘗試下載大文件(如 1gb 或更大)時程序卡住了。我用它下載了 100mgb 和 300mgb 左右的文件,一切正常。下載器在提供標頭 Accept-Ranges 的服務器上使用。下面我將向您展示實現和主要部分,但首先讓我解釋一下。接受范圍:字節在這個實現中,我創建了一個 http.Client 來使用我請求的文件部分設置標題范圍,之后我提出了請求。為了存儲這個請求的響應,我創建了一個臨時文件,并將響應直接復制到這個文件中。這樣做的想法是避免將整個響應復制到內存中。這是實現:func DownloadPart(wg *sync.WaitGroup, tempName string, url string, part string) { //setting up the client to make the request client := http.Client{} request, err := http.NewRequest("GET", url, nil) //setting up the requests request.Header.Set("Range", part) response, err := client.Do(request) checkError(err, "fatal") defer response.Body.Close() //creating the temporary file and copying // the response to it file, err := os.Create(tempName) checkError(err, "panic") defer file.Close() _, err = io.Copy(file, response.Body) checkError(err, "fatal") defer wg.Done()}這個函數在各種 goroutine 中被調用,所以當 gorputine 結束下載部分文件時,我使用了 WaitGroup 來減少計數器。在所有這些 goroutine 結束后,我將不同的臨時文件加入到一個文件中。這是join函數的實現func joinFiles(name string) { finalFile, err := os.OpenFile(name, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { log.Panicln(err.Error()) } defer finalFile.Close() files, err := ioutil.ReadDir(".") for _, f := range files { tempData, err := ioutil.ReadFile(f.Name()) if err != nil { log.Panicln(err.Error()) } if f.Name() != finalFile.Name() { finalFile.Write(tempData) os.Remove(f.Name()) } }}現在我將向您展示使用這些功能的主要功能部分//start, end and rest are used to set the Range header in the requests //threads are the number of goroutines to used in the downloadvar wg sync.WaitGroupwg.Add(threads)//initializing the goroutinesfor i := 0; i < threads; i++ { part := fmt.Sprintf("bytes=%d-%d", start, end) start = end + 1 if i == threads-1 { end = end + step + rest } else { end = end + step }如果有辦法改進這個實現?
1 回答

守候你守候我
TA貢獻1802條經驗 獲得超10個贊
我認為這里最大的問題是您如何將文件拼接在一起。調用ioutil.ReadAll
會將整個文件的內容讀入內存,并且由于您對所有部分都執行此操作,因此您可能會在內存中結束整個文件的內容(GC 可能會在中間運行并釋放其中的一些內容。)要做的是io.Copy
在文件上使用(在用打開它之后os.Open
)將其復制到最終文件中。這樣您就不必將內容存儲在內存中。
- 1 回答
- 0 關注
- 92 瀏覽
添加回答
舉報
0/150
提交
取消