在 Go 中的多线程中按块下载文件

Download files by chunks in multiple threads in Go

我需要在多线程中逐块下载文件。 例如,我有 1k 个文件,每个文件 ~100Mb-1Gb,我只能按 4096Kb 的块下载这些文件(每个 http get 请求只给我 4kb)。

在一个线程中下载它可能会很长时间,所以我想下载它们,假设在 20 个线程中(一个线程一个文件)我还需要在每个线程中下载几个块, 同时.

有没有例子可以说明这种逻辑?

这是一个如何设置并发下载器的例子。需要注意的是带宽、内存和磁盘 space。您可以通过尝试一次做很多事情来消耗带宽,内存也是如此。您下载的文件很大,因此内存可能是个问题。另一件需要注意的事情是,通过使用 gorountines 你会失去请求顺序。因此,如果返回字节的顺序很重要,那么这将不起作用,因为您最终必须知道 assemble 文件的字节顺序,这意味着最好一次下载一个,除非您实现了一种跟踪顺序的方法(可能是某种带有互斥锁的全局映射[order int][]字节以防止竞争条件)。不涉及 Go 的替代方法(假设您有一台简单的 unix 机器)是使用 Curl 参见此处 http://osxdaily.com/2014/02/13/download-with-curl/

package main

import (
    "bytes"
    "fmt"
    "io"
    "io/ioutil"
    "log"
    "net/http"
    "sync"
)

// now your going to have to be careful because you can potentially run out of memory downloading to many files at once..
// however here is an example that can be modded
func downloader(wg *sync.WaitGroup, sema chan struct{}, fileNum int, URL string) {
    sema <- struct{}{}
    defer func() {
        <-sema
        wg.Done()
    }()

    client := &http.Client{Timeout: 10}
    res, err := client.Get(URL)
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    var buf bytes.Buffer
    // I'm copying to a buffer before writing it to file
    // I could also just use IO copy to write it to the file
    // directly and save memory by dumping to the disk directly.
    io.Copy(&buf, res.Body)
    // write the bytes to file
    ioutil.WriteFile(fmt.Sprintf("file%d.txt", fileNum), buf.Bytes(), 0644)
    return
}

func main() {
    links := []string{
        "url1",
        "url2", // etc...
    }
    var wg sync.WaitGroup
    // limit to four downloads at a time, this is called a semaphore
    limiter := make(chan struct{}, 4)
    for i, link := range links {
        wg.Add(1)
        go downloader(&wg, limiter, i, link)
    }
    wg.Wait()

}

您可以在 aws-go-sdk 中查看实现。 https://github.com/aws/aws-sdk-go-v2/blob/main/feature/s3/manager/download.go

  1. 创建n个并发go例程
  2. 下载 n go routine
  3. 中的块
  4. 使用writer.WriteAt()查找并写入特定位置。