Golang如何实现并发文件下载

使用goroutine与channel实现Go语言并发文件下载,通过WaitGroup等待任务完成,并用带缓冲channel控制最大并发数防止资源耗尽。

在Go语言中实现并发文件下载,核心思路是利用goroutine和channel来并行发起多个HTTP请求,同时控制并发数量防止资源耗尽。通过合理分配任务、合并结果和错误处理,可以高效地完成多个文件的下载。

使用Goroutine与WaitGroup控制并发

每个文件下载任务可以在独立的goroutine中执行,使用sync.WaitGroup等待所有任务完成。这种方式简单直接,适合数量不多的并发下载。

示例代码结构:

func downloadFile(url, filename string) error {
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
file, err := os.Create(filename)
if err != nil {
    return err
}
defer file.Close()

io.Copy(file, resp.Body)
return nil

}

func main() { urls := []string{"https://www./link/18c578f830e2897ac30e2c72e6e122a1", "https://www./link/c2e4a009b0acaea484f4384134824c69"} var wg sync.WaitGroup

for i, url := range urls {
    wg.Add(1)
    go func(u string, idx int) {
        defer wg.Done()
        err := downloadFile(u, fmt.Sprintf("file_%d", idx))
        if err != nil {
            log.Printf("下载失败: %s, 错误: %v", u, err)
        }
    }(url, i)
}
wg.Wait()

}

限制最大并发数避免系统过载

当下载任务较多时,无限制地启动goroutine可能导致内存或连接数爆炸。可以通过带缓冲的channel作为信号量来控制最大并发数。

常见做法:

  • 创建容量为N的channel,表示最多允许N个并发任务
  • 每个goroutine开始前从channel接收信号,结束后释放
  • 主协程循环发送任务,通过channel实现调度
semaphore := make(chan struct{}, 10) // 最多10个并发
for i, url := range urls {
    go func(u string, idx int) {
        semaphore <- struct{}{} // 获取令牌
        err := downloadFile(u, fmt.Sprintf("file_%d", idx))
        if err != nil {
            log.Println("下载出错:", err)
        }
        <-semaphore // 释放令牌
    }(url, i)
}
// 等待所有任务完成(可通过额外channel或time.Sleep简化)
time.Sleep(2 * time.Second)

结合Context实现超时与取消

真实场景中需要对下载任务设置超时机制,避免长时间阻塞。使用context.WithTimeout可统一管理生命周期。

关键点:

  • 为每个请求绑定context,传递超时控制
  • 在http.Get中使用带context的client
  • 主逻辑可通过context提前取消所有任务
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

req, _ := http.NewRequestWithContext(ctx, "GET", url, nil) resp, err := http.DefaultClient.Do(req)

基本上就这些。并发下载的核心是合理调度goroutine,控制资源使用,加上必要的错误和超时处理,就能稳定高效地运行。