草庐IT

concurrency - Golang并发下载死锁

coder 2024-07-11 原文

我想在 go 中并行下载文件,但我的代码永远不会退出:

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "path/filepath"
    "sync"
)

func download_file(file_path string, wg sync.WaitGroup) {
    defer wg.Done()
    resp, _ := http.Get(file_path)
    defer resp.Body.Close()
    filename := filepath.Base(file_path)
    file, _ := os.Create(filename)
    defer file.Close()

    size, _ := io.Copy(file, resp.Body)
    fmt.Println(filename, size, resp.Status)
}

func main() {
    var wg sync.WaitGroup

    file_list := []string{
        "http://i.imgur.com/dxGb2uZ.jpg",
        "http://i.imgur.com/RSU6NxX.jpg",
        "http://i.imgur.com/hUWgS2S.jpg",
        "http://i.imgur.com/U8kaix0.jpg",
        "http://i.imgur.com/w3cEYpY.jpg",
        "http://i.imgur.com/ooSCD9T.jpg"}
    fmt.Println(len(file_list))
    for _, url := range file_list {
        wg.Add(1)
        fmt.Println(wg)
        go download_file(url, wg)

    }
    wg.Wait()
}

这是什么原因?我看过这里:Golang download multiple files in parallel using goroutines但我没有找到解决办法。 调试此类代码的最佳方法是什么?

最佳答案

正如 Tim Cooper 所说,您需要将 WaitGroup 作为指针传递。如果你在你的代码上运行 go vet 工具,它会给你这个警告:

$ go vet ex.go
ex.go:12: download_file passes Lock by value: sync.WaitGroup contains sync.Mutex
exit status 1

我建议使用可以在您保存文件时为您执行此操作的编辑器。例如go-plus用于 Atom。

至于代码,我认为你应该像这样重构它:

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "path/filepath"
    "sync"
)

func downloadFile(filePath string) error {
    resp, err := http.Get(filePath)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    name := filepath.Base(filePath)

    file, err := os.Create(name)
    if err != nil {
        return err
    }
    defer file.Close()

    size, err := io.Copy(file, resp.Body)
    if err != nil {
        return err
    }
    fmt.Println(name, size, resp.Status)
    return nil
}

func main() {
    var wg sync.WaitGroup

    fileList := []string{
        "http://i.imgur.com/dxGb2uZ.jpg",
        "http://i.imgur.com/RSU6NxX.jpg",
        "http://i.imgur.com/hUWgS2S.jpg",
        "http://i.imgur.com/U8kaix0.jpg",
        "http://i.imgur.com/w3cEYpY.jpg",
        "http://i.imgur.com/ooSCD9T.jpg"}
    fmt.Println("downloading", len(fileList), "files")
    for _, url := range fileList {
        wg.Add(1)
        go func(url string) {
            err := downloadFile(url)
            if err != nil {
                fmt.Println("[error]", url, err)
            }
            wg.Done()
        }(url)
    }
    wg.Wait()
}

我不喜欢传递 WaitGroup 并且更喜欢保持函数简单、阻塞和顺序,然后在更高级别将并发缝合在一起。这使您可以选择按顺序执行所有操作,而无需更改 downloadFile

我还添加了错误处理和固定名称,因此它们是驼峰式。

关于concurrency - Golang并发下载死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30139279/

有关concurrency - Golang并发下载死锁的更多相关文章

  1. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  2. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  3. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  4. ruby - 下载位置 Selenium-webdriver Cucumber Chrome - 2

    我将Cucumber与Ruby结合使用。通过Selenium-Webdriver在Chrome中运行测试时,我想将下载位置更改为测试文件夹而不是用户下载文件夹。我当前的chrome驱动程序是这样设置的:Capybara.default_driver=:seleniumCapybara.register_driver:seleniumdo|app|Capybara::Selenium::Driver.new(app,:browser=>:chrome,desired_capabilities:{'chromeOptions'=>{'args'=>%w{window-size=1920,1

  5. ruby-on-rails - 获取并发布相同匹配项的请求 - 2

    在我的路线文件中我有:match'graphs/(:id(/:action))'=>'graphs#(:action)'如果是GET请求(工作)或POST请求(不工作),我想匹配它我知道我可以使用以下方法在资源中声明POST请求:post'/'=>:show,:on=>:member但是我怎样才能为比赛做到这一点呢?谢谢。 最佳答案 如果你同时想要POST和GETmatch'graphs/(:id(/:action))'=>'graphs#(:action)',:via=>[:get,:post]编辑默认值可以设置如下match'g

  6. ruby-on-rails - HTTParty 的内存问题和下载大文件 - 2

    这会导致Ruby出现内存问题吗?我知道如果大小超过10KB,Open-URI会写入TempFile。但是HTTParty会在写入TempFile之前尝试将整个PDF保存到内存吗?src=Tempfile.new("file.pdf")src.binmodesrc.writeHTTParty.get("large_file.pdf").parsed_response 最佳答案 您可以使用Net::HTTP。参见thedocumentation(特别是标题为“流媒体响应机构”的部分)。这是文档中的示例:uri=URI('http://e

  7. ruby - 强制浏览器下载文件而不是打开文件 - 2

    我要下载http://foobar.com/song.mp3作为song.mp3,而不是让Chrome在其native中打开它浏览器中的播放器。我怎样才能做到这一点? 最佳答案 您只需要确保发送这些header:Content-Disposition:attachment;filename=song.mp3;Content-Type:application/octet-streamContent-Transfer-Encoding:binarysend_file方法为您完成:get'/:file'do|file|file=File.

  8. ruby - 检查网络文件是否存在,而不下载它? - 2

    是否可以在不实际下载文件的情况下检查文件是否存在?我有这么大的(~40mb)文件,例如:http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm这与ruby​​不严格相关,但如果发件人可以设置内容长度就好了。RestClient.get"http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm",headers:{"Content-Length"=>100} 最佳答案

  9. ruby-on-rails - Rubygems - 包在哪里下载? - 2

    当你安装一个新包时,例如,'geminstallfb-graph',文件下载到哪里了? 最佳答案 使用此命令查找特定gem的安装位置:gemwhich例如:gemwhichfb-graph 关于ruby-on-rails-Rubygems-包在哪里下载?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/13200065/

  10. ruby-on-rails - Rails add_index 算法 : :concurrently still causes database lock up during migration - 2

    为了防止在迁移到生产站点期间出现数据库事务错误,我们遵循了https://github.com/LendingHome/zero_downtime_migrations中列出的建议。(具体由https://robots.thoughtbot.com/how-to-create-postgres-indexes-concurrently-in概述),但在特别大的表上创建索引期间,即使是索引创建的“并发”方法也会锁定表并导致该表上的任何ActiveRecord创建或更新导致各自的事务失败有PG::InFailedSqlTransaction异常。下面是我们运行Rails4.2(使用Acti

随机推荐