为了账号安全,请及时绑定邮箱和手机立即绑定

同时多次下载同一文件

同时多次下载同一文件

Go
慕桂英4014372 2023-07-17 17:49:01
我同时从配置对象切片(其中每个配置对象包含需要下载的 URL)下载文件(使用 WaitGroup),但是当我使用并发时,我会在每次执行时获得完全相同的数据。我相信我将下面的所有内容都包含在一个最小的可重复示例中。这是我的进口:package mainimport (    "encoding/json"    "fmt"    "io"    "io/ioutil"    "log"    "net/http"    "os"    "path"    "path/filepath"    "strconv"    "strings"    "sync")循环遍历我的对象并执行 go 例程来下载每个文件的方法如下:func downloadAllFiles(configs []Config) {    var wg sync.WaitGroup    for i, config := range configs {        wg.Add(1)        go config.downloadFile(&wg)    }    wg.Wait()}基本上,我的功能是将文件从 URL 下载到 NFS 上存储的目录中。这是下载功能:func (config *Config) downloadFile(wg *sync.WaitGroup) {    resp, _ := http.Get(config.ArtifactPathOrUrl)    fmt.Println("Downloading file: " + config.ArtifactPathOrUrl)    fmt.Println(" to location: " + config.getNfsFullFileSystemPath())    defer resp.Body.Close()    nfsDirectoryPath := config.getBaseNFSFileSystemPath()    os.MkdirAll(nfsDirectoryPath, os.ModePerm)    fullFilePath := config.getNfsFullFileSystemPath()    out, err := os.Create(fullFilePath)    if err != nil {        panic(err)    }    defer out.Close()    io.Copy(out, resp.Body)    wg.Done()}这是 Config 结构的最小部分:type Config struct {    Namespace                 string                      `json:"namespace,omitempty"`    Tenant                    string                      `json:"tenant,omitempty"`    Name                      string                      `json:"name,omitempty"`    ArtifactPathOrUrl         string                      `json:"artifactPathOrUrl,omitempty"`}以下是实例/辅助函数:func (config *Config) getDefaultNfsURLBase() string {    return "http://example.domain.nfs.location.com/"}func (config *Config) getDefaultNfsFilesystemBase() string {    return "/data/nfs/location/"}func (config *Config) getBaseNFSFileSystemPath() string {    basePath := filepath.Dir(config.getNfsFullFileSystemPath())    return basePath}
查看完整描述

1 回答

?
qq_笑_17

TA贡献1818条经验 获得超7个赞

我很确定你的猜测


这个问题让我想起如果您尝试运行带有闭包的 for 循环并最终将单个对象实例锁定到循环中并在同一个对象上重复执行,会发生什么。


是正确的。简单的修复方法是“分配给本地变量”,例如


for _, config := range configs {

    wg.Add(1)

    cur := config

    go cur.downloadFile(&wg)

}

但我不喜欢将 waitgroup 作为参数的 API,所以我建议


for _, config := range configs {

    wg.Add(1)

    go func(cur Config) {

       defer wg.Done()

       cur.downloadFile()

    }(config)

}

并将downloadFile签名更改为func (config *Config) downloadFile()并删除wg其中的用法。


查看完整回答
反对 回复 2023-07-17
  • 1 回答
  • 0 关注
  • 144 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信