gpt4 book ai didi

go - 同时多次下载同一文件

转载 作者:行者123 更新时间:2023-12-02 04:49:00 27 4
gpt4 key购买 nike

我同时从配置对象 slice (其中每个配置对象包含需要下载的 URL)下载文件(使用 WaitGroup),但是当我使用并发时,我会在每次执行时获得完全相同的数据。

我相信我包含了下面的所有内容作为一个最小的可重现示例。

这是我的导入:

package main

import (
"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
}

func (config *Config) getNfsFullFileSystemPath() string {
// basePath is like: /data/nfs/location/
trimmedBasePath := strings.TrimSuffix(config.getDefaultNfsFilesystemBase(), "/")
fileName := config.getBaseFileName()
return trimmedBasePath + "/" + config.Tenant + "/" + config.Namespace + "/" + config.Name + "/" + fileName
}

以下是我获取配置并解码它们的方法:

func getConfigs() string {
b, err := ioutil.ReadFile("pulsarDeploy_example.json")
if err != nil {
fmt.Print(err)
}
str := string(b) // convert content to a 'string'
return str
}

func deserializeJSON(configJson string) []Config {
jsonAsBytes := []byte(configJson)
configs := make([]Config, 0)
err := json.Unmarshal(jsonAsBytes, &configs)
if err != nil {
panic(err)
}
return configs
}

作为一个最小的示例,我认为 pulsarDeploy_example.json 文件的数据应该有效:

[{   "artifactPathOrUrl": "http://www.java2s.com/Code/JarDownload/sample/sample.jar.zip",
"namespace": "exampleNamespace1",
"name": "exampleName1",
"tenant": "exampleTenant1"
},

{
"artifactPathOrUrl": "http://www.java2s.com/Code/JarDownload/sample-calculator/sample-calculator-bundle-2.0.jar.zip",
"namespace": "exampleNamespace1",
"name": "exampleName2",
"tenant": "exampleTenant1"
},
{
"artifactPathOrUrl": "http://www.java2s.com/Code/JarDownload/helloworld/helloworld.jar.zip",
"namespace": "exampleNamespace1",
"name": "exampleName3",
"tenant": "exampleTenant1"
},
{
"artifactPathOrUrl": "http://www.java2s.com/Code/JarDownload/fabric-activemq/fabric-activemq-demo-7.0.2.fuse-097.jar.zip",
"namespace": "exampleNamespace1",
"name": "exampleName4",
"tenant": "exampleTenant1"
}
]

(请注意,示例文件 URL 只是我在网上抓取的随机 Jars。)

当我运行代码时,它不会下载每个文件,而是重复下载同一文件,并将信息打印到控制台(从 下载文件: 到位置: 行)对于每个对象都是完全相同的(而不是打印每个对象唯一的消息),这绝对是一个并发问题。

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

是什么导致了这种行为?如何解决?

最佳答案

我很确定你的猜测

This issue reminds me of what happens if you try to run a for loop with a closure and end up locking a single object instance into your loop and executing repeatedly on the same object.

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

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 用法。

关于go - 同时多次下载同一文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57795207/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com