我同时从配置对象切片(其中每个配置对象包含需要下载的 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其中的用法。
- 1 回答
- 0 关注
- 144 浏览
添加回答
举报
0/150
提交
取消