performance - 简单网络服务器上的 Golang 高 CPU 使用率无法理解为什么?

标签 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 )
    }
}

最佳答案

问题是 fmt.Fprintf()需要一个格式字符串:

func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)

然后您将一个 8 KB 的大格式字符串传递给它。 fmt 包必须分析格式字符串,它不是按原样到达输出的东西。最肯定的是,这就是占用您 CPU 的原因。

如果随机字符串包含特殊的 % 符号,那甚至会使您的情况变得更糟,因为那时 fmt.Fprintf() 可能会期待更多您不希望的参数“交付”,因此 fmt 包还必须(将)在输出中包含错误消息,例如:

fmt.Fprintf(os.Stdout, "aaa%bbb%d")

输出:

aaa%!b(MISSING)bb%!d(MISSING)

使用fmt.Fprint()相反,它不需要格式字符串:

fmt.Fprint(w, str)

或者更好的是,将随机字符串转换为字节 slice 一次,然后继续写入:

data := []byte(str)
for i := 0; i < iter; i++ {
    if _, err := w.Write(data); err != nil {
        // Handle error, e.g. return
    }
}

传送大量数据——没有比在循环中编写准备好的字节 slice 更快的解决方案了(如果改变 slice 的大小,速度可能会稍微快一些)。如果您的解决方案仍然“缓慢”,那可能是由于您的 RandStringBytes() 函数我们一无所知,或者如果您使用其他处理程序或您的输出可能被压缩(gzipped)一些框架(确实使用相对较高的 CPU)。此外,如果接收响应的客户端也在您的计算机上(例如浏览器),它或防火墙/防病毒软件可能会检查/分析恶意代码的响应(这也可能是资源密集型的)。

关于performance - 简单网络服务器上的 Golang 高 CPU 使用率无法理解为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40342340/

相关文章:

go - 基于主机地址的HTTP速率限制

android - 计算 Android 进程的 CPU 使用率

Python 列表切片性能

c# - IQueryable、ICollection、IList 和 IDictionary 接口(interface)之间的区别

performance - html 5 Canvas 和 css 动画的奇怪帧率问题

PHP - 回显还是不回显?

go - 拆分 int 以分隔数字以便遍历每个数字

go - 使用自己的结构(解码的 JSON)初始化外部 lib 结构会产生类型错误

java - 在什么时候短 sleep 会增加而不是减少 CPU 利用率

PHP 100% CPU 使用率与 Sublime Text 3