三.高质量编程简介及编码规范2
2.1.性能优化建议 Benchmark
- 性能表现需要实际数据衡量
- Go语言提供了支持基准性能测试的benchmark
go test -bench=. -benchmem
2.2.性能优化建议 Slice
2.2.1.slice 预分配内存
注意点: 尽可能在使用 make() 初始化切片时提供容量信息
对于切片的理解:
-
切片本质是一个数组片段的描述
- 包括数组指针
- 片段的长度
- 片段的容量(不改变内存分配情况下的最大长度)
-
切片操作并不会复制切片指向的元素
-
创建一个新的切片会复用原来切片的底层数组
2.2.2.slice 大内存未释放
-
在已有切片基础上创建切片, 不会创建新的底层数组
-
场景
- 原切片较大, 代码在原切片基础上新建小切片
- 原底层数组在内存中有引用, 得不到释放
-
可使用 copy 替代 re-slice
go test -run=. -v
2.3.性能优化建议 Map
-
map 预分配内存
- 不断向 map 中添加元素的操作会触发 map 的扩容
- 提前分配好空间可以减少内存拷贝和 Rehash 的消耗
- 建议根据实际需求提前预估好需要的空间
2.4.性能优化建议 字符串处理
- 使用 stirngs.Builder
性能对比:
"+" 拼接 < stirngs.Builder = bytes.Buffer < strings.Buffer
分析:
- 字符串在Go语言中是不可变类型, 占用内存大小是固定的
- 使用 + 每次都会重新分配内存
- strings.Builder, bytes.Buffer 底层都是 []byte 数组
- 内存扩容策略, 不需要每次拼接重新分配内存
2.5.性能优化建议 空结构体
空结构体节省内存
-
空结构体 struct{} 实例不占据任何的内存空间
-
可作为各种场景下的占位符使用
- 节省资源
- 空结构体本身具备很强的语义, 即这里不需要任何值, 仅作为占位符
2.6.性能优化建议 atomic包
- 锁的实现是通过操作系统来实现, 属于系统调用
- atomic 操作是通过硬件实现, 效率比锁高
- sync.Mutex 应该用来保护一段逻辑, 不仅仅用于保护一个变量
- 对于非数值操作, 可以使用 atomic.Value, 能承载一个 interface{}