性能调优简记 | 青训营笔记

135 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记

调优的目的是提升各种性能效率指标,属于没有标准答案的问题。这代表我们应该尽量量化调优的结果。 有个好消息是 go 语言自身携带了benchmark测试工具,一个简单的示例如下:

func BenchmarkXXXXX(b *testing.B) {
	for i := 0; i < b.N; i++ {
        //xxxxxxx
        // 这里将被测试的代码片段
	}
}

按照这种固定的函数签名,以及前缀就算是写了基准测试的一个用例。 然后使用下面的命令就可以得到benchmark测试结果。

go test -bench=.  -benchmem

这是测试到整个包的函数,-benchmem则表示收集内存使用信息,如果仅仅需要测试某个具体的函数可以使用下面这种。

go test -bench $BenchmarkXXXX$  -benchmem
在具体的执行结果中可以看到执行效率,内存占用,分配次数等情况。这样我们之后的调优就有了数据支撑。基本的调优目标是尽可能低的执行耗时、内存占用、分配次数具体到实际应用中,在我们常用的数据结构mapslice都会涉及到内存的分配,根据上面的目标,我们应该在申请mapslice结构时尽量指明大小。另外slice由于切片机制的存在,它会有内存泄漏的风险(原因在于切片会引用原有的数据,这会造成没法释放,因此这时应该使用copy)。比如一个1000的切片,我们只使用1大小的切片,那么有高达999性能优化上,类似的还有string的拼接,每次操作都会重新分配,老生常谈的问题了,基本上所有使用不可变字符串类的语言都有这个问题。比如在Java中不应该使用string+运算做拼接,而应该使用基于可变数组构造的的StringBuilder之类的工具类。Go语言中也是类似的,使用底层基于数组的工具类。而由于可变性,同样的,如果可以的话也应该尽量声明具体的大小。更进一步的调优需要使用pprof之类的工具详细分析性能热点。这里就不展开了。 在具体的执行结果中可以看到执行效率,内存占用,分配次数等情况。 这样我们之后的调优就有了数据支撑。 基本的调优目标是尽可能低的**执行耗时、内存占用、分配次数**。 --- 具体到实际应用中,在我们常用的数据结构map、slice都会涉及到内存的分配,根据上面的目标,我们应该在申请map、slice结构时尽量指明大小。 另外slice由于切片机制的存在,它会有内存泄漏的风险(原因在于切片会引用原有的数据,这会造成没法释放,因此这时应该使用copy)。 比如一个1000的切片,我们只使用1大小的切片,那么有高达999%的内存泄露。 性能优化上,类似的还有string的拼接,每次操作都会重新分配,老生常谈的问题了,基本上所有使用不可变字符串类的语言都有这个问题。比如在Java中不应该使用string 的 + 运算做拼接,而应该使用基于可变数组构造的的StringBuilder之类的工具类。Go语言中也是类似的,使用底层基于数组的工具类。而由于可变性,同样的,如果可以的话也应该尽量声明具体的大小。 ------------------- 更进一步的调优需要使用pprof之类的工具详细分析性能热点。这里就不展开了。