go例程挂起下载大文件

时间:2017-12-28 15:07:27

标签: go

我正在尝试编写一个可下载一系列图像的应用程序。

  • 130 116kb images(works)
  • 50 500kb图像(作品)
  • 130 500kb图像(最终挂起)
  • 230张116kb图像(最终挂起)

go go go1.9.2 darwin / amd64

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "sync"
)

func main() {

    var urls []string

    // var smallImage = "https://s3.amazonaws.com/golangplayground/116kb.jpeg" //116kb
    var largeImage = "https://s3.amazonaws.com/golangplayground/SampleJPGImage_500kbmb.jpg" //500kb
    for i := 0; i < 130; i++ {
        urls = append(urls, largeImage)
    }

    var wg sync.WaitGroup
    wg.Add(len(urls))
    var inc = 0
    for _, val := range urls {
        inc += 1
        go saveResourceFromURLToDisk(val, "./foo", &wg, inc)
    }
    wg.Wait()
    fmt.Println("done.")
}

func saveResourceFromURLToDisk(url string, writeTo string, wg *sync.WaitGroup, inc int) error {
    defer wg.Done()

    response, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
        return err
    }
    defer response.Body.Close()

    localPath := fmt.Sprintf("%s/%d", writeTo, inc)
    file, err := os.Create(localPath)
    if err != nil {
        log.Fatal(err)
        return err
    }
    defer file.Close()

    _, err = io.Copy(file, response.Body)
    if err != nil {
        log.Fatal(err)
        return err
    }

    fmt.Println(localPath)
    return nil
}

2 个答案:

答案 0 :(得分:1)

这可能是一个网络问题。 Web浏览器对打开同一服务器的会话数量有限制的原因。

如果同时打开一堆TCP会话,几乎所有TCP会话都会丢失数据包。然后他们都会尝试在大约相同的时间重试,丢失更多的数据包。这只是一大堆失败。

在打开每个GET请求之间放置一个小延迟,或限制自己同时从同一服务器下载4-8个。

答案 1 :(得分:0)

我在Zan的帮助下找到了答案,通过在每个5个请求中分解我的例程......这样我就可以利用一些并行性来限制我正在创建的开放连接的数量。

它有点幼稚,我想知道是否有人有更优雅的解决方案。

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "sync"
)

func main() {

    var urls []string   
    // var smallImage = "https://s3.amazonaws.com/golangplayground/116kb.jpeg" //116kb
    var largeImage = "https://s3.amazonaws.com/golangplayground/SampleJPGImage_500kbmb.jpg" //500kb
    for i := 0; i < 150; i++ {
        urls = append(urls, largeImage)
    }

    var inc = 0;
    for x:=0; x < len(urls)/5; x++ {
        var wg sync.WaitGroup       
        for y:=0; y<5; y++ {
            wg.Add(1)           
            go saveResourceFromURLToDisk(urls[x*y], "./foo", &wg, inc)
            inc += 1
        }
        wg.Wait()                                   
    }

    fmt.Println("done.")
}

func saveResourceFromURLToDisk(url string, writeTo string, wg *sync.WaitGroup, inc int) error {
    defer wg.Done()

    response, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
        return err
    }
    defer response.Body.Close()

    localPath := fmt.Sprintf("%s/%d", writeTo, inc)
    file, err := os.Create(localPath)
    if err != nil {
        log.Fatal(err)
        return err
    }
    defer file.Close()

    _, err = io.Copy(file, response.Body)
    if err != nil {
        log.Fatal(err)
        return err
    }

    fmt.Println(localPath)
    return nil
}