简介:
- 性能优化的前提是满足正确可靠,简洁清晰等质量因素
- 性能优化是综合评估,有时候时间效率和空间效率可能对立
性能优化建议–Benchmark
go语言提供了支持基准性能测试,如何使用得去查一查
slice
-
slice预分配内存,尽可能在使用make()初始化切片时提供容量信息
data := make([]int,0) data := make([]int,0,10)
-
切片的底层实现就是可扩容的链表
-
陷阱:大内存未释放
- 在已有的切片上创建切片,不会创建新的底层数组
- 原切片较大,代码在原切片的基础上新建小切片
- 原底层数组在内存中引用,得不到释放
-
可使用copy替代re-slice
func GetLastBySlice(origin []int) []int{ return origin[len(origin) - 2:] } // 下面这个节省的空间更多 fun getLastByCopy(origin []int) []int{ result := make([]int,2) copy(result,origin[len(origin) - 2:]) return result }
map
- map预分配内存
- 不断地向map中添加新元素地操作会触发map地扩容
- 提前分配好空间可以减少内存拷贝和Rehash地消耗
- 建议提前根据实际需求预估好需要的空间大小
strings.Buider进行字符串处理
- 使用+拼接性能最差,strings.Buider,bytes.Buffer相近,strings。Buffer更快
- 字符串在go里面时不可变类型,占用大小固定
- 使用+每次都会重新分配内存
- strings.Buider和bytes.Buffer底层都是使用[]byte数组
使用空结构体节省内存
使用atomic包
-
锁的实现是通过操作系统来实现,属于系统调用, 调用成本很高
-
atomic操作是通过硬件实现,效率比锁高
-
sync.Mutex应该用来保护一段逻辑,。不仅仅用于保护一个变量
-
对于非值操作,可以使用atomic.Value,能承载一个interface{}
type atomicCounter struct{ i int32 } func AtomicAddOne(c *atomicCounter){ atomic.AddInt32(&c.i,1) } type mutexCounter struct{ i int32 m sync.Mutex } func MutexAddOne(c *mutexCounter){ c.m.Lock() c.i++ c.m.UnLock() }
小结:
- 避免常见的性能陷阱可以保证大部分程序的功能
- 普通应用代码,不要一味地追求程序的性能
- 越高级的性能优化手段越容易出现问题
- 在满足正确可靠,简洁清晰的质量要求的前提下提高程序性能