Golang并发下载死锁

时间:2015-05-09 11:21:04

标签: concurrency go

我想在go中并行下载文件,但我的代码永远不会退出:

-s svm type,        3 for epsilon-SVR
-t kernel type,     2 for radial basis function
-c cost parameter C of epsilon-SVR
-g width parameter gamma for RBF kernel
-p epsilon for epsilon-SVR

是什么原因?我看过这里:Golang download multiple files in parallel using goroutines但我找不到解决办法。 调试此类代码的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

正如Tim Cooper所说,你需要传递WaitGroup作为指针。如果您在代码上运行go vet工具,它会向您发出此警告:

$ go vet ex.go
ex.go:12: download_file passes Lock by value: sync.WaitGroup contains sync.Mutex
exit status 1

我建议使用能够在保存文件时为您执行此操作的编辑器。例如,Atom的go-plus

至于代码,我认为你应该重新构建它:

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "path/filepath"
    "sync"
)

func downloadFile(filePath string) error {
    resp, err := http.Get(filePath)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    name := filepath.Base(filePath)

    file, err := os.Create(name)
    if err != nil {
        return err
    }
    defer file.Close()

    size, err := io.Copy(file, resp.Body)
    if err != nil {
        return err
    }
    fmt.Println(name, size, resp.Status)
    return nil
}

func main() {
    var wg sync.WaitGroup

    fileList := []string{
        "http://i.imgur.com/dxGb2uZ.jpg",
        "http://i.imgur.com/RSU6NxX.jpg",
        "http://i.imgur.com/hUWgS2S.jpg",
        "http://i.imgur.com/U8kaix0.jpg",
        "http://i.imgur.com/w3cEYpY.jpg",
        "http://i.imgur.com/ooSCD9T.jpg"}
    fmt.Println("downloading", len(fileList), "files")
    for _, url := range fileList {
        wg.Add(1)
        go func(url string) {
            err := downloadFile(url)
            if err != nil {
                fmt.Println("[error]", url, err)
            }
            wg.Done()
        }(url)
    }
    wg.Wait()
}

我不喜欢传递WaitGroup并且更喜欢保持函数简单,阻塞和顺序,然后在更高级别将并发性拼接在一起。这使您可以选择按顺序执行所有操作,而无需更改downloadFile

我还添加了错误处理和固定名称,因此它们是camelCase。

答案 1 :(得分:1)

根据Calab的回应,您的方法绝对没有错,您所要做的就是将指针传递给sync.WaitGroup

func download_file(file_path string, wg *sync.WaitGroup) {
    defer wg.Done()
    ......
}
.....
        go download_file(url, &wg)
.....

playground