性能优化指南
Go语言提供了支持基准性能测试
性能表现需要实际数据衡量
Go语言提供了支持基准性能测试的benchmark工具
go test -bench=, -benchmem
性能优化建议——Slice
比如说在创建切片的时候提前分配内存,这样可以减少内存分配的次数
切片的实现原理: 切片里面带有指针长度,还有容量,当容量没有满的时候,就直接添加进去,然后增加长度,但是当容量满了的时候,就要给这个数组做一个扩容,很麻烦
就是扩容的本质还是使用原来的数组
另一个陷阱:假如创建新的数组,只引用了原来数组的几个元素,那么原来数组里面的其他元素就没办法释放,造成资源浪费,所以使用copy代替slice
当map使用的时候最好也用预分配做一个处理,他的扩容机制和切片很像
字符串拼接的时候,直接使用加号的性能是最差的,可以使用strings.Builder或者bytes.Buffer来进行拼接,
因为字符串在go语言中,是不可变的类型,每次拼接需要重新分配内存,但是上面两种方式的实现方式都是byte数组,拼接的时候,就是扩容,不用重新分配内存
- 避免常见的性能陷阱可以保证大部分程序的性能
- 普通应用代码,不要一味的追求程序的性能
- 越高级的性能优化越容易出现问题
- 满足正确可靠,简介清晰的质量要求的前提下提高程序性能
pprof测试工具
基本使用方法
性能调优原则:
要依靠数据而不是猜测
要定位最大瓶颈,而不是细枝末节
不要过早优化
不要过度优化
会把函数调用都显示出来,并且生成函数链,这样就可以直观地看到使用了哪些函数,并且函数的执行顺序是怎样的
可视化执行指令,并且执行之后会在浏览器上面显示执行效果
pprof—采样过程和原理
采样对象:函数调用和他们占用的时间
采样率:100/秒,固定值
采样时间:从手动启动到手动结束
操作系统
每10ms向进程发送一次SIGPROF信号
进程
每次接收到SIGPROF信号会记录调用堆栈
写缓冲
每100ms读取已经记录的调用栈写入输出流
其实里面最后输出的记录由两部分组成:
第一部分就是:进程的执行时间
第二部分就是:已经记录的调用栈里面的一些信息
采样程序通过内存分配器在堆上分配和释放内存,记录分配/释放的大小和数量
采样率:每分配512KB记录一次,可在运行开头修改,1为每次分配记录
采样时间:从程序运行开始到采样时
采样指标:alloc_space , alloc_object ,inuse _space ,inuse_objects
计算方式:inuse = alloc - free
是不是要是效率比较差的时候,调用的函数就会少,堆里面的东西就少,虽然每100ms记录一次,但是实际记录的函数是比较少的,这样就是固定时间来比较调用函数的数量
采样阻塞操作的次数和耗时:超过阈值才会被记录,每次加一
采样抢夺所的次数,只有固定比例的锁操作,才会被记录,每次加一
性能调优案例
不同的参数可能会执行不同的方法
从各个维度来评估
每个机器的性能都是不一样的
日志的使用要规范一些,否则会出现很多没用的日志
高并发场景优化不足
就是高峰期和平常的需求量不同,需要优化一下,提高项目的瓶颈
通过返回值来判断优化是否正确:记录之前的返回值,优化之后在记录一次,进行比较