同时下载同一文件多次

devinbost:

我正在同时从一片配置对象(每个配置对象包含需要下载的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。)

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

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

是什么引起了这种现象,我该如何解决?

艾因:

我很确定你的猜测

这个问题使我想起了如果您尝试使用闭包运行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用法。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

内存映射同一文件多次?

多次读取同一文件的Python

无法多次发布同一文件

多次发出Concat同一文件的声音

多次关闭并打开同一文件错误

在PHP中多次包含同一文件

多次上传同一文件

如何使wget不多次下载同一文件(带有和不带有扩展名)

多次打开和关闭同一文件与长时间打开文件

可以使用同一文件对象多次读取文件吗?

MVC 5多个文件上传多次上传同一文件

在C文件阅读中:如何在同一文件上多次执行fgets?

多个可执行文件同时访问同一文件夹

从ftp下载文件并保存在同一文件夹中

对同一文件进行多次ajax调用以在同一文件中执行不同的代码?

多次导入作为参考导入的同一文件,而不是复制

Sublime Text 2和3:多次打开同一文件

使用“ a”模式多次添加到同一文件

多个Java进程可以同时读取同一文件吗?

我们可以同时打开多个FileWriter流到同一文件吗?

在Java中同时读取和写入同一文件

使用C ++同时读取和写入同一文件

从 PowerShell 中的 Invoke-RestMethod 同时读取和写入同一文件

同时在同一文件上运行几个sed命令

使用tee同时输出多个命令到同一文件是否安全?

Node.js同时读取流并将其写入同一文件

如何在仍写入同一文件的同时过滤掉特定行?

如何从多个URL下载同一文件以提高速度?

SFTP集成-SftpInboundFileSynchronizer-如何不再次下载同一文件