3

Ubuntu 13.04でgo 1.1 develを使用しています

go version devel +ebe8bca920ad Wed May 15 15:34:47 2013 +1000 linux/386

http://golang.org/doc/faq#goroutinesによると

ブロッキング システム コールの呼び出しなどによってコルーチンがブロックされると、ランタイムは、同じオペレーティング システム スレッド上の他のコルーチンを別の実行可能なスレッドに自動的に移動して、ブロックされないようにします。

私はゴルーチンを使用して大きなファイルをチャンクでダウンロードできるダウンローダを作成しようとしていますが、これは私が思いついた最高のゴルーチンです:

func download(uri string, chunks chan int, offset int, file *os.file) {
    for current := range chunks {

        fmt.println("downloading range: ", current, "-", current+offset)

        client := &http.client{}
        req, _ := http.newrequest("get", uri, nil)
        req.header.set("range: ", fmt.sprintf("bytes=%d-%d", current, current+offset))
        resp, err := client.do(req)
        if err != nil {
            panic(err)
        }
        defer resp.body.close()
        body, err := ioutil.readall(resp.body)
        if err != nil {
            panic(err)
        }
        file.write(body)
    }
}

完全なスクリプトは、https://github.com/tuxcanfly/godown/blob/master/godown.goで入手できます。

ファイルは正しくダウンロードされ、保存されていますが、2 番目のチャンクは最初のチャンクが終了したときにのみ開始されることがわかります。

チャンク化されたダウンロードを並行して実行するべきではありませんか、それとも何か間違っていますか?

4

1 に答える 1

17

チャンクをダウンロードするゴルーチンは 1 つだけです。

64 行目:

go download(*download_url, chunks, offset, file)

おそらくあなたが望むのは:

for i := 0; i < *threads; i++ {
    go download(*download_url, chunks, offset, file)
}

*threadsこれにより、チャンクが一度にダウンロードされます。


並行処理が機能するようになった後、おそらく 29 行目が意図したとおりに機能しないことに気付くでしょう。チャンク 1 がチャンク 2 の前に終了した場合、パーツは順不同で書き込まれます。代わりにhttp://golang.org/pkg/os/#File.WriteAtを使用することもできます。


Range ヘッダーにも 2 つの問題があります。

  1. 残りはダウンロードしません。ファイル サイズが 3002 で 3 つのスレッドがある場合、0 ~ 1000、1000 ~ 2000、2000 ~ 3000 が要求され、最後の 2 バイトはダウンロードされません。
  2. バイト範囲は包括的です。つまり、(前の例でわかるように) 一部のバイトを 2 回ダウンロードしていることになります。バイト 1000 と 2000 が 2 回要求されます。もちろん、正しい場所に書き込んでいる限り、それほど問題はないはずです。

2 番目は、19 行目を次のように変更するだけで簡単に修正できます。

req.Header.Set("Range: ", fmt.Sprintf("bytes=%d-%d", current, current+offset))

これに

req.Header.Set("Range: ", fmt.Sprintf("bytes=%d-%d", current, current+offset-1))

Range ヘッダーの詳細については、RFC2616 のセクション 14.35 を読むことをお勧めします。

于 2013-05-20T05:38:10.833 に答える