这是我参与「第五届青训营」伴学笔记创作活动的第 6 天
性能优化的前提是保证代码质量,同时很多时候时间效率和空间效率是对立的,今天的内容主要是针对go语言特性学习相关的性能优化方法
性能优化
常见方法
性能表现需要实际数据来衡量,go语言中有提供基准性能测试的benchmark工具,可以通过benchmark工具观察函数执行平均时间和内存占用
1、Slice
切片是我们在go中常用的数据结构,在使用make()方法初始化切片时最好提供初始容量信息,由于slice本质上还是针对数组的描述,如果不去指定size,slice自身会有默认的最大容量,每当超过slice最大容量时,切片会不断请求更大的内存,而这一过程会浪费很多时间空间。
此外在使用slice时应避免大内存未释放的问题,如果在原有切片基础上直接新建切片,会导致之前切片的底层数组一直处于被引用的状态从而无法释放,此时我们使用copy方法可以避免这一问题
此外在使用slice时应避免大内存未释放的问题,如果在原有切片基础上直接新建切片,会导致之前切片的底层数组一直处于被引用的状态从而无法释放,此时我们使用copy方法可以避免这一问题
2、Map
与Slice相同的,在使用make()方法初始化时最好提供初始容量信息,不断向map中添加元素会出发map的扩容操作,提前分配好内存可以减少内存拷贝和Rehash的消耗
此外在使用slice时应避免大内存未释放的问题,如果在原有切片基础上直接新建切片,会导致之前切片的底层数组一直处于被引用的状态从而无法释放,此时我们使用copy方法可以避免这一问题
此外在使用slice时应避免大内存未释放的问题,如果在原有切片基础上直接新建切片,会导致之前切片的底层数组一直处于被引用的状态从而无法释放,此时我们使用copy方法可以避免这一问题
3、字符串处理
在go语言中的字符串处理其实和java类似,使用"+"号处理是性能最差的方式,字符串在go中是不可变类型,占用内存大小固定,每次使用加号都会重新分配内存,而strings.Builder,bytes.Buffer底层都是[]byte数组,相比之下strings.Buffer比前两者更快
4、空结构体
使用空结构体struct{}示例不占内存,可作为各种场景下的占位符
4、atomic包
可以使用atomic包来替代锁,因为锁是通过操作系统实现,属于系统调用。atomic操作通过硬件实现,效率比锁更高,关于sync.Mutex的使用,我们应用它来保护一段逻辑而不是一个变量
总结
当然很多时候其实并没有必要在普通应用中追求过高的性能,很多时候会增加错误的风险,所以提高性能虽然重要,但前提是能保证代码质量