性能优化指南 | 青训营笔记

80 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

1. Benchmark

(1) 如何使用

😋 性能表现需要实际数据衡量

😋 Go语言提供了支持基准性能测试的 benchmaek 工具

😋 命令:go test -bench=. -benchmen

😋 结果说明

image.png

2. Silce

(1) slice预分配内存

😋 尽可能在使用 make() 初始化切片时提供容量信息

image.png 😋 切片本质是一个数组片段的描述

🌹 包括数组指针
🌹 片段的长度
🌹 片段的容量(不改变内存分配情况下的最大长度切片操作并不复制切片指向的元素
🌹 创建一个新的切片会复用原来切片的底层数组

😋 切片操作并不复制切片指向的元素

😋 创建一个新的切片会复用原来切片的底层数组

(2)大内存未释放

😋 在已有切片基础上创建切片,不会创建新的底层数组

😋 场景

🌹 原切片较大,代码在原切片基础上新建小切片
​
🌹 原底层数组在内存中有引用,得不到释放

😋 可使用 copy 替代 re-slice

命令:go test -run =. -v

3. Map

😋 预分配内存

image.png

🌹 不断向 map 中添加元素的操作会触发 map 的扩容
🌹 提前分配好空间可以减少内存拷贝和 Rehash 的消耗
🌹 建议根据实际需求提前预估好需要的空间

4. 字符串处理

(1)字符串连接性能:strings.Builder > bytes.Buffer > +

image.png

🌹 字符串在 Go 语言中是不可变类型,占用内存大小是固定的
🌹 使用 + 每次都会重新分配内存
🌹 strings.Builder,bytes.Buffer 底层都是 []byte 数组]
🌹 内存扩容策略,不需要每次拼接重新分配内存
🌹 bytes.Buffer 转化为字符串时重新申请了一块空间
🌹 strings.Builder 直接将底层的[]byte 转换成了字符串类型返回

(2)建议指定初始化长度

image.png

5. 空结构体

😋 节省内存

🌹 空结构体 struct实例不占据任何的内存空间

🌹 可作为各种场景下的占位符使用
 🤠 节省资源
 🤠 空结构体本身具备很强的语义,即这里不需要任何值,仅作为占位符

🌹 应用场景
 🤠 实现set,可以考虑用map替代,只需要用到map的键,值可以用空结构体
 

6. atomic包

😋 锁的实现是通过操作系统来实现,属于系统调用

😋 atomic 操作是通过硬件实现,效率比锁高

😋 sync.Mutex 应该用来保护一段逻辑,不仅仅用于保护一个变量

😋 对于非数值操作,可以使用 atomic.Value,能承载一个 interface {}

7. 小结

😋 避免常见的性能陷阱可以保证大部分程序的性能

😋 普通应用代码,不要一味地追求程序的性能

😋 越高级的性能优化手段越容易出现问题

😋 在满足正确可靠、简洁清晰的质量要求前提下提高程序性能