这是我参与「第五届青训营」笔记创作活动的第七天。
一:本堂课的重点内容
性能优化建议
二:详细知识点如下
1、benchmark
go语言提供了支持基准性能测试的工具:benchmark
1)作用
可以用来测试某个函数或者任何代码的执行时间
2)用法
import (
"fmt"
"testing"
)
func BenchmarkSprint(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
fmt.Sprint(i)
}
}
运行:go test -bench=. -run=none 命令得到以下结果:
运行benchmark基准测试也要用到 go test 命令,不过我们后面需要加上-bench=参数,接受一个表达式作为参数,匹配基准测试的函数,"."一个点表示运行所有的基准测试。
因为默认情况下 go test 会运行单元测试,为了防止单元测试的输出影响我们查看基准测试的结果,可以使用-run=匹配一个从来没有的单元测试方法,过滤掉单元测试的输出。
2、slice
1)slice预分配内存
2)大内存未释放
3、Map
map预分配内存
建议:
4、字符串处理
1)使用strings.Builder
原因:
5、空结构体
使用空结构体节省内存,不占存储空间,
6、atomic
1)atomic介绍
sync/atomic包提供了原子操作的能力,直接有底层CPU硬件支持,因而一般要比基于操作系统API的锁方式效率高些;这些功能需要非常小心才能正确使用。 除特殊的底层应用程序外,同步更适合使用channel或sync包的功能。
2)扩展知识
对于原子操作, 还有几条具体的使用建议:
不要把内部使用的原子值暴露给外界。比如, 声明一个全局的原子变量并不是一个正确的做法, 这个变量的访问权限最起码也应该是包级私有的。
如果不得不让包外, 或模块外的代码使用你的原子值, 那么可以声明一个包级私有的原子变量, 然后再通过一个或多个公开的函数, 让外界间接地使用到它。注意, 这种情况下不要把原子值传递到外界, 不论是传递原子值本身还是它的指针值。
如果通过某个函数可以向内部的原子值存储值的话, 那么就应该在这个函数中先判断被存储值类型的合法性。若不合法, 则应该直接返回对应的错误值, 从而避免 panic 的发生。
如果可能的话, 我们可以把原子值封装到一个数据类型中, 比如一个结构体类型。这样, 我们既可以通过该类型的方法更加安全地存储值, 又可以在该类型中包含可存储值的合法类型信息.
三、课后个人总结
普通代码不能一味追求程序的性能,应该一步一个脚印,循序渐进,越高级的性能优化手段越容易出现问题,应该在代码质量合格的前提下提高性能。 无论是内存、CPU还是前端页面,都有很多的profile工具,解决了一两个最大的性能问题,往往就可以突破瓶颈。要先通过这些profile工具找到真正的问题所在。否则很有可能做无用功。2-8法则在很多情况下都是成立的。
四、引用参考
events.jianshu.io/p/a318318c2… blog.csdn.net/zhghost/art… blog.csdn.net/wan212000/a…