2017-12-28 9 views
0

イメージの範囲をダウンロードするアプリケーションを作成しようとしています。大きなファイルのダウンロード時に実行ルーチンがハングアップする

  • 130 116キロバイト画像(作品)
  • 50 500キロバイト画像(作品)
  • 130 500キロバイトイメージ(最終的にハング)
  • 230 116キロバイトイメージ(最終的にハング)

外出バージョン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 
} 
+0

コードに間違いはありません。 S3のGETまたは同時のダウンロード制限を打つ可能性があります。 – abhink

+3

何百もの同時接続を開くことは非効率的であり、接続やファイル記述子の制限によってはおそらく動作しません。 – JimB

答えて

1

これはおそらく、 orkの問題。 Webブラウザには、同じサーバに対して開くセッションの数に制限があります。

同時に複数のTCPセッションを開くと、ほとんどすべてがパケットを失います。その後、彼らはすべて同じ時間に再試行しようとし、より多くのパケットを失う。それは単に失う大きな山です。

各GET要求を開くか、同じサーバーから4〜8回の同時ダウンロードに制限するのが少し遅れて配置してください。

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 
} 
+0

5つのゴルーチンを作成して、すべて同じチャンネルで聞きます。別のゴルーチンまたはメインプログラムがURL文字列をチャネルに送ります。すべてのURLが送信された後、送信者はチャネルを閉じる必要があります。ゴルーチンは終了時に終了する必要があります。送信者は、あなたがすでに行っているのと同じように、待機グループを待ちます。これにより、プログラムが終了する前にすべてのURLが取得され、ダウンロードされます。 –

+0

ありがとうZan私はそれを試してみましょう。 – nwkeeley

関連する問題