我在Ubuntu 13.04上使用了1.1开发
go version devel +ebe8bca920ad Wed May 15 15:34:47 2013 +1000 linux/386
根据http://golang.org/doc/faq#goroutines
当协程阻止时,例如通过调用阻止系统调用, 运行时自动将其他协程移动到同一个协同程序上 操作系统线程到一个不同的,可运行的线程,所以他们不会 被阻止。
我正在尝试编写一个下载程序,可以使用goroutines以块的形式下载大文件 这是我提出的最好的goroutine:
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
即使文件正在下载并正确保存,我也可以看到第二个块开始了 只有在第一次完成时。
分块下载不应该并行运行,还是我做错了?
答案 0 :(得分:17)
你只有一个goroutine下载块。
第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标题也有两个问题。
通过从
更改第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标头的更多信息,建议您阅读Section 14.35 in RFC2616