注:本文的原文 Debugging performance issues in Go programs 由 Dmitry Vyukov 在 05/10/2014 - 07:06 编写
注:原文太长,你们要看所有的请看原文,其余的部分,后续慢慢翻译。php
让咱们假设你想提高你的GO程序的性能。这里有一些工具能够帮助你完成这个任务。这些工具能帮助你定位多种类型的热点(CPU,IO,内存),你为了可以显著提高程序性能,你必须专一于热点发生的地方。尽管如此,另一个结果是可能的--这些工具能帮助你肯定程序中明显的性能缺陷。例如,当你在每一个程序启动的时候,你能够在每次查询的以前准备一个 SQL 语句。另一个例子是若是一个 O(N^2)
算法在某种程度上陷入了一个明显存在而且指望的 O(N)
状况。为了肯定这样的状况,你须要完整性的检查你在 profiles 中看到的。例如第一种状况下大量的时间花费在 SQL 语句的准备上,这已经超越了告警线了。html
一样重要的是要理解性能影响的各类边界因素。例如,一个程序经过 100 Mbps 的带宽链接通信,而且它已经使用超过 90 Mbps,这里就没有什么能够对这程序作的来提高它的性能了。这些相似的边界因素包括 磁盘 IO,内存消耗和计算任务。golang
考虑到这一点,咱们能够查看这些可用的工具。web
注意:这些工具可能相互干扰,例如,精确的内存分析可能影响CPU分析。goroutine 阻塞分析可能影响调度追踪等等,隔离地使用这些工具以便获得更加精确的信息。算法
注意:这里全部的描述都是基于 Go1.3 版本的windows
Go runtime 包含了内建的 CPU 分析器,这显示了函数消耗的 CPU 时间百分比,这里你有3种方式访问它:服务器
go test
命令的 -cpuprofile 标记。例如,以下命令:$ go test -run=none -bench=ClientServerParallel4 -cpuprofile=cprof net/http
cprof
文件。$ go tool pprof --text http.test cprof
go tool pprof
来获得最完整的列表。import net/http/pprof
而且用以下命令收集概要文件:$ go tool pprof --text mybin http://myserver:6060:/debug/pprof/profile
if *flagCpuprofile != "" { f, err := os.Create(*flagCpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() }
这份概要文件会被写入指定的文件中,想象它和第一个选项同样的命令行方式。网络
这里是一个使用 --web
选项产生的直观的概要文件示例:app
你可使用 -list=funcname
选项来研究单个函数,下面的 概要文件显示了在 append 函数中所花费的时间:svg
. . 93: func (bp *buffer) WriteRune(r rune) error { . . 94: if r < utf8.RuneSelf { 5 5 95: *bp = append(*bp, byte(r)) . . 96: return nil . . 97: } . . 98: . . 99: b := *bp . . 100: n := len(b) . . 101: for n+utf8.UTFMax > cap(b) { . . 102: b = append(b, 0) . . 103: } . . 104: w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r) . . 105: *bp = b[:n+w] . . 106: return nil . . 107: }
你能够在这里找到 pprof
工具的详细信息和描述的数字图。
当它不能解锁堆栈的时候,这里有关于分析器使用的3条特别条目:GC, System and ExternalCode。GC 表示内存垃圾回收的时间花费,见下面的内存分析器和垃圾收集器跟踪优化建议部分。System 表示 goroutine 调度花费的时间,堆栈管理代码以及其余辅助的 runtime 代码。ExternalCode 表示本地动态库花费的时间。
这里有些提示关于如何解释说明你在 profile 中看到的信息。
若是不少时间花费在 runtime.mallocgc
函数,程序可能在小内存分配上面花费过多。 profile 会告诉你分配从哪里来,看内存分析器建议如何优化的部分。
若是不少时间花费在 channel
操做部分,sync.Mutex
代码和其余 synchronization primitives
或者是系统组件,程序可能在承受资源竞争。考虑重构程序,以消除对共享资源的频繁访问。常见的技术包括分片、分区,本地缓冲/批量处理和写时拷贝技术。
若是不少时间花费在 syscall.Read/Write
上面,程序可能在小读写上面花费代价太大。Bufio 包装 os.File
或是 net.Conn
能对这种状况有帮助。
若是不少时间花费在 GC 组件上面,程序不是分配了太多的临时对象就是 heap size 设置太小致使垃圾回收频繁发生。请看垃圾收集器跟踪和内存分析器优化建议部分。
注意:
CPU profiler
目前不能在 darwin 上工做
注意: 在 windows 服务器上你须要安装 Cygwin, Perl and Graphviz 来生成 svg/web 格式的概要文件
注意: 在 Linux 上你能够尝试 perf system profiler,它不能解锁 GO 的堆栈,可是它能分析而且解锁cgo/SWIG
代码和内核。因此它在定位分析本地/内核性能瓶颈上很是有用。