性能优化|青训营笔记
这是我参与[第五届青训营]伴学笔记创作活动的第3天,今天学习的是性能优化部分
简介
- 性能优化是综合评估,有时候时间效率和空间效率可能冲突
- 性能优化的前提是满足正确可靠、简洁清晰等质量因素
性能测试工具-Benchmark(go语言自带)
写一个benchmark测试
- 基准测试代码文件必须是_test.go结尾,和单元测试一样;
- 基准测试的函数以Benchmark开头;
- 参数须为 *testing.B;
- 基准测试函数不能有返回值;
- b.ResetTimer是重置计时器,这样可以避免for循环之前的初始化代码的干扰;
- b.N是基准测试框架提供的,Go会根据系统情况生成,不用用户设定,表示循环的次数,因为需要反复调用测试的代码,才可以评估性能;
执行测试的五个结果依次为:1.cpu核数 2.测试次数 3.每次消耗时间 4.每次消耗内存 5.每次执行申请了几次内存
性能优化建议
Slice
-
使用时尽量预分配内存
因为如果不先申请内存,当切片容量不够时,会自动扩容申请内存,会比较耗费时间。所以尽量在创建切片时就预置容量。
-
在已有切片的基础上创建切片,尽量用copy代替直接创建切片。
因为代码在原切片上新建切片,原切片不需要的那段内存得不到释放,比较消耗资源
map
-
预分配内存,和slice一样 (不断向map中添加元素的操作会触发map的扩容,提前分配好空间可以减少内存拷贝和Rehash的消耗)
map和slice都需要提前预估好需要的空间
字符串处理
用string.Builder处理速度最快
- 使用‘+’号进行字符串拼接性能最差,strings.Builder,bytes.Buffer相近,strings.Buffer更快
分析
字符串在Go语言中是不可变类型,占用内存大小是固定的,使用+每次都会重新分配内存 strings.Builder,bytes.Buffer底层都是[]byte数组内存扩容策略,不需要每次拼接重新分配内存。
结构体
- 空结构体struct{}的实例不占内存空间。其中不含有任何数据,那有什么意义呢?我们常把它作为占位符使用
线程安全
用atomic包的时间性能比加锁更好
- 锁的实现是通过操作系统来实现,属于系统调用,占用资源多。
- atomic操作是通过硬件实现,效率比锁高