【发布时间】:2016-09-23 12:05:24
【问题描述】:
考虑这个程序:
package main
import (
"net/http"
"os"
)
var url = "https://upload.wikimedia.org/wikipedia/commons/f/fe/FlumeRide%2C_Liseberg_-_last_steep_POV.ogv"
func main() {
response, _ := http.Get(url)
defer response.Body.Close()
f, _ := os.Create("output.ogv")
defer f.Close()
_, err = io.Copy(f, response.Body)
}
它具有与wget $url 相同的功能,运行时间约为7.3 秒(对我而言)。 wget 只需 ~4.6 秒。为什么差距这么大?这个简单的 Python 程序在将整个视频写入磁盘之前将其加载到内存中,大约需要 5.2 秒:
import requests
url = "https://upload.wikimedia.org/wikipedia/commons/f/fe/FlumeRide%2C_Liseberg_-_last_steep_POV.ogv"
def main():
r = requests.get(url)
with open('output.ogv','wb') as output:
output.write(r.content)
if __name__ == "__main__":
main()
分析
我对此进行了相当多的调查。以下是我采取的一些方法:
- 在
io.Copy中使用不同的缓冲区大小 - 使用其他读取器/写入器
- 并发/并行
- 下载较大的文件
不同的缓冲区大小
我使用io.CopyBuffer 尝试了许多不同的缓冲区大小,我发现32KB 的默认缓冲区大小让我获得了最佳速度(仍然比wget 和Python 的reqeusts 慢1.6 到1.8 倍)。
其他读取器/写入器
所有其他读取器和写入器都比使用io.Copy 慢得可以忽略不计。我尝试使用 (f *File) Write 和其他一些缓冲读取器/写入器。
并发/并行
我什至编写了一个相当长的程序,它在标头中使用range 来并行下载此文件,但正如预期的那样,我的速度似乎没有任何显着提高。
更大的文件
我下载的文件是这个文件的三倍多,我的 Go 实现仍然比 wget 和 requests 慢 1.5 到 2 倍。
其他注意事项
- 在计时之前我正在构建一个二进制文件。
- 绝大多数时间都花在实际编写/复制
response.Body上。无论我下载的文件有多大,这部分似乎只占了大约 0.3 秒的经过时间。
那我做错了什么?我应该期望 GET 请求在 Go 中花费的时间更长吗?
【问题讨论】:
-
什么版本的 go?
-
你是在使用
go run执行程序吗? -
@MellowMarmot 不,我正在构建一个二进制文件,然后再计时。
-
@superfell 我正在使用 go version 1.7 darwin/amd64
-
wget 最有可能使用 gzip 但 go 没有。