golang在简单的webserver上使用高cpu无法理解为什么?

时间:2016-10-31 12:37:24

标签: performance go cpu-usage

所以我有一个简单的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 )
    }
}

1 个答案:

答案 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)。此外,如果收到响应的客户端也在您的计算机上(例如浏览器),它 - 或防火墙/防病毒软件 - 可能会检查/分析恶意代码的响应(也可能是资源密集型)。