同时多次下载同一文件

我同时从配置对象切片(其中每个配置对象包含需要下载的 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

}



慕桂英4014372
浏览 153回答 1
1回答

qq_笑_17

我很确定你的猜测这个问题让我想起如果您尝试运行带有闭包的 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其中的用法。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go