所以我有一个简单的net / http网络服务器。它所做的只是提供100MB的随机字节,我打算用它来进行网络速度测试。我对100mb端点的处理程序非常简单(粘贴在下面)。代码工作正常,我得到我的随机字节文件,问题是当我运行这个并且有人下载这些100兆字节时,该程序的CPU最高可达150%并保持在那里直到此处理程序完成运行。我在这里做错了吗?我该怎么做才能提高这个处理程序的性能?
func downloadHandler(w http.ResponseWriter, r *http.Request) {
str := RandStringBytes(8192); //generates 8192 bytes of randomness
sz := 1000*1000*100; //100Megabytes
iter := sz/len(str)+1;
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Length", strconv.Itoa( sz ))
for i := 0; i < iter ; i++ {
fmt.Fprintf(w, str )
}
}
答案 0 :(得分:6)
问题是fmt.Fprintf()
需要格式字符串:
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
然后你传递一个8 KB格式的大字符串。 fmt
包必须分析格式字符串,它不是按原样到达输出的东西。最明确的是这就是吃CPU的原因。
如果随机字符串包含特殊的%
符号,那么甚至会使您的情况变得更糟,因为fmt.Fprintf()
可能会期待您没有提供的其他参数&#34; ,因此fmt
包还必须(将)在输出中包含错误消息,例如:
fmt.Fprintf(os.Stdout, "aaa%bbb%d")
输出:
aaa%!b(MISSING)bb%!d(MISSING)
使用fmt.Fprint()
而不是格式字符串:
fmt.Fprint(w, str)
甚至更好,将随机字符串转换为字节切片一次,然后继续写下:
data := []byte(str)
for i := 0; i < iter; i++ {
if _, err := w.Write(data); err != nil {
// Handle error, e.g. return
}
}
提供大量数据 - 您不会获得比在循环中编写准备好的字节切片更快的解决方案(如果您改变切片的大小,可能会稍微有点)。如果您的解决方案仍然“慢”,那可能是由于我们不了解的RandStringBytes()
功能,或者如果您使用其他功能,您的输出可能会被压缩(gzip)处理程序或一些框架(使用相对较高的CPU)。此外,如果收到响应的客户端也在您的计算机上(例如浏览器),它 - 或防火墙/防病毒软件 - 可能会检查/分析恶意代码的响应(也可能是资源密集型)。