最简单的方法
常量与变量
- 多处使用的变量提取为常量
- 局部变量使用
:=
初始化
- 局部变量
列表型
数据,可以使用数组替代切片
数据类型
切片
初始化时预分配容量
map
初始化时预分配容量
map
的键类型尽可能选择整型
map
记得及时删除过期数据,定期重置稀疏map
- 优先使用
[]byte
而非string
(标准库和第三方大多数 API 都是[]byte
),避免两者之间类型转换,还可以通过引用机制
进行复用
- 当
列表型
元素是稀疏的(例如有很多0
或者nil
),可以使用map
作为存储结构
- 当
map
只有键
没有值
并且键
的分布连续时,可以使用数组
或切片
实现
- 如果
切片
元素是复杂的数据类型,使用for i, _ := range slice
方式遍历,避免复制元素带来的性能损耗
- 尽量避免
hot path
上面的内存分配、加锁解锁等操作
- 尽量使用具体的数据类型而非
any
- 尽量使用
缓冲通道
而非非缓冲通道
- 小对象使用
值传递
,而非指针传递
- 对于非持久性对象,优先分配到栈
- 大多数情况下,使用指针类型作为方法的
接收者
- 复杂对象参数传递时传递其指针
- 复杂对象存储到切片时存储其指针
- 使用空结构体
struct{}
优化内存
- 注意
内存对齐
标准库
- 整数转字符串使用
strconv.Itoa
- 较长的字符串拼接使用
strings.Builder
- 使用对象池
sync.Pool
复用对象
- 循环中使用
time.After
时记得复用
- 复用
HTTP
链接
- 使用
sync/atomic
包避免锁操作
- 使用 IO 缓冲,如
bufio.NewWrite()
bufio.NewReader()
IO 密集型
场景并发操作
- 尽可能避免使用
反射
- 尽可能使用
读写锁
替代互斥锁
- 尽可能减小
锁的粒度
,使用完成后立即释放
hot path
上尽可能避免使用defer
释放锁
hot path
上的encoding/binary
相关操作可以手动实现,避免标准库实现中的反射
- 正则表达式如果多次使用,使用
regexp.Compile()
提前编译完成
- 使用
runtime.Callers
打印堆栈信息而非runtime.Stack
- 使用
singleflight
防止缓存击穿
- 合理使用
内联优化
备注
笔者在测试上面的
Tips
有效性时,Go 版本为 go1.19 linux/amd64
, 这些 Tips 可能随着 Go 版本的变化不再适用,读者遇到具体的性能问题时,应该首先分析具体业务场景,以严格的测试结果为准,切莫按图索骥。扩展阅读

转载申请
本作品采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,商业转载请联系作者获得授权。