亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用 goroutines 下載文件?

使用 goroutines 下載文件?

Go
慕碼人2483693 2021-11-08 19:17:04
我是 Go 的新手,我正在學習如何使用 goroutines。我有一個下載圖片的功能:func imageDownloader(uri string, filename string) {    fmt.Println("starting download for ", uri)    outFile, err := os.Create(filename)    defer outFile.Close()    if err != nil {        os.Exit(1)    }    client := &http.Client{}    req, err := http.NewRequest("GET", uri, nil)    resp, err := client.Do(req)    defer resp.Body.Close()    if err != nil {        panic(err)    }    header := resp.ContentLength    bar := pb.New(int(header))    rd := bar.NewProxyReader(resp.Body)    // and copy from reader    io.Copy(outFile, rd)}當我作為另一個函數的一部分單獨調用時,它會完全下載圖像并且沒有截斷的數據。但是,當我嘗試修改它以使其成為 goroutine 時,圖像通常會被截斷或零長度文件。func imageDownloader(uri string, filename string, wg *sync.WaitGroup) {    ...    io.Copy(outFile, rd)    wg.Done()}func main() {var wg sync.WaitGroupwg.Add(1)go imageDownloader(url, file, &wg)wg.Wait()}我是否錯誤地使用了 WaitGroups?什么可能導致這種情況,我該如何解決?更新:解決了。我已將該wg.add()函數置于循環之外。:(
查看完整描述

3 回答

?
繁星coding

TA貢獻1797條經驗 獲得超4個贊

雖然我不確定究竟是什么導致了您的問題,但這里有兩個選項可以讓您恢復正常工作。

首先,查看如何使用同步庫中的等待組示例,嘗試defer wg.Done()在函數的開頭調用以確保即使 goroutine 意外結束,等待組也正確遞減。

其次,io.Copy返回一個你沒有檢查的錯誤。無論如何,這都不是很好的做法,但在您的特定情況下,它會阻止您查看復制例程中是否確實存在錯誤。檢查并妥善處理。它還返回寫入的字節數,這也可能對您有所幫助。



查看完整回答
反對 回復 2021-11-08
?
PIPIONE

TA貢獻1829條經驗 獲得超9個贊

您的示例在使用 WaitGroups 方面沒有任何明顯錯誤。只要您調用wg.Add()的數量與您啟動的 goroutine 的數量相同,或者每次啟動新的 goroutine 時都將其增加 1,這應該是正確的。

但是,您在 goroutine 中調用os.Exitpanic針對某些錯誤條件,因此如果您有多個這些正在運行,無論是否使用 WaitGroups,其中任何一個的失敗都會終止所有這些。如果它在沒有恐慌消息的情況下失敗,我會看看這os.Exit(1)條線。

defer wg.Done()在函數開始時使用 go 也是一種很好的做法,這樣即使發生錯誤,goroutine 仍然會減少其計數器。這樣,如果 goroutine 之一返回錯誤,您的主線程將不會在完成時掛起。


查看完整回答
反對 回復 2021-11-08
?
一只名叫tom的貓

TA貢獻1906條經驗 獲得超3個贊

我會在您的示例中進行的一項更改是defer當您使用Done. 我認為這defer ws.Done()應該是您函數中的第一條語句。


我喜歡WaitGroup的簡單。但是,我不喜歡我們需要傳遞對 goroutine 的引用,因為這意味著并發邏輯將與您的業務邏輯混合。


所以我想出了這個通用函數來為我解決這個問題:


// Parallelize parallelizes the function calls

func Parallelize(functions ...func()) {

    var waitGroup sync.WaitGroup

    waitGroup.Add(len(functions))


    defer waitGroup.Wait()


    for _, function := range functions {

        go func(copy func()) {

            defer waitGroup.Done()

            copy()

        }(function)

    }

}

所以你的例子可以這樣解決:


func imageDownloader(uri string, filename string) {

    ...

    io.Copy(outFile, rd)

}


func main() {

    functions := []func(){}

    list := make([]Object, 5)

    for _, object := range list {

        function := func(obj Object){ 

            imageDownloader(object.uri, object.filename) 

        }(object)

        functions = append(functions, function)

    }


    Parallelize(functions...)        


    fmt.Println("Done")

}

如果你想使用它,你可以在這里找到它https://github.com/shomali11/util


查看完整回答
反對 回復 2021-11-08
  • 3 回答
  • 0 關注
  • 265 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號