Go语言性能优化指南:性能优化建议| 青训营

68 阅读4分钟

一、简介

  • 性能调优的前提是满足正确可靠、简洁清晰等质量因素
  • 性能优化的目标是使系统能够更快地完成任务、更高效地利用资源,并提供更好的用户体验
  • 性能优化是综合评估,有时候时间效率和空间效率可能对立
  • 针对Go语言特性,介绍Go相关的性能优化建议

二、Benchmark

基准测试(benchmark)是 go testing 库提供的,用来度量程序性能,算法优劣的利器。

指定一个时间(默认是1秒),看测试对象在达到时间上限时,最多能被执行多少次和在此期间测试对象内存分配情况。

基本规则

  • 准测试的代码文件必须以_test.go结尾
  • 基准测试的函数必须以Benchmark开头,必须是可导出的
  • 基准测试函数必须接受一个指向Benchmark类型的指针作为唯一参数
  • b.ResetTimer是重置计时器,这样可以避免for循环之前的初始化代码的干扰
  • 最后的for循环很重要,被测试的代码要放到循环里
  • b.N是基准测试框架提供的,表示循环的次数,因为需要反复调用测试的代码,才可以评估性能

常用命令

go test -bench=. -benchmem
  1. 使用 -bench=. 标记,它接受一个表达式作为参数,匹配基准测试的函数,. 表示运行所有基准测试。
  2. 使用 -benchmem 提供每次操作分配内存的次数,以及每次操作分配的字节数。
  3. 使用 -run=none 匹配单元测试方法,这里使用 none 是因为没有这个名字的单元测试方法,等效于过滤掉单元测试的输出。
  4. 使用 -benchtime=3s 指定测试的时间,例如3秒,测试时间默认是1秒。
  5. 使用 -count=3 用来设置 benchmark 的轮数。例如,进行3轮benchmark。

三、slice预分配内存

在Go语言中,可以使用内置的make函数来创建一个具有预分配内存的切片。预分配内存可以提高切片的性能,减少动态内存分配的次数。

make函数的语法是:make([]T, length, capacity),其中T是切片的元素类型,length是切片的初始长度,capacity是切片的预分配容量。

内存占用与释放

在Go语言中,切片的内存占用和释放是由运行时系统自动管理的。当创建一个切片时,运行时系统会自动分配一块内存来存储切片的元素。当切片不再被使用时,运行时系统会自动释放该内存。

当切片的长度超过了其容量时,运行时系统会自动为切片分配更多的内存,并将原始数据复制到新的内存中。这个过程被称为切片的扩容。切片的扩容是自动进行的,开发者无需手动管理。

当切片不再被引用时,也就是没有任何变量指向该切片时,运行时系统会自动回收切片所占用的内存。这是通过垃圾回收机制来实现的。

虽然Go语言的内存管理是自动的,但是为了避免不必要的内存占用,我们可以通过将不再使用的切片设置为nil来显式释放内存。将切片设置为nil会使其不再被引用,从而触发垃圾回收机制来回收切片所占用的内存。

以下是一个示例:

package main

import "fmt"

func main() {
    s := make([]int, 0, 5)
    
    // 使用切片...
    
    // 释放切片的内存
    s = nil
    
    // 手动触发垃圾回收
    // runtime.GC()
    
    // 使用其他变量...
}

四、map预分配内存

在Go语言中,可以使用make函数来创建一个预分配了指定容量的mapmake函数的第二个参数是map的容量,表示可以存储的键值对数量。

通过预分配容量,我们可以看到map在每次添加键值对时,容量会逐渐增加。这样,就可以减少map的动态内存分配次数,提高性能。

需要注意的是,预分配的容量并不会限制map的长度。map可以根据需要动态扩展,直到达到运行时系统限制的最大长度。