持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情 本文主要是关于错误和异常处理并对于slice,map,string等数据结构提供了性能优化建议
1.2.5错误和异常处理
Errors.New与fmt.Errorf的对比:
err := errors.New("your first demo error")
errWithCtx = fmt.Errorf("index %d is out of bounds", i)
复杂错误
需要将错误包装和解包
在生成跟踪链后,同时结合错误的判断方法来确认调用链中是否有关注的错误出现,其好处是每一层调用方可以补充自己对应的上下文,方便跟踪排查问题,来确定问题的根本原因在哪里 如:
把err关联到fmt.Errorf创建的错误中
适用于当错误是一套错误链时,来确定具体是哪里,出现何种错误。例如上图所表示的错误是不存在
在错误链上获取特定种类的错误,使用errors.As
如图,表示路径错误 并把问题的路径打印出来了
errors.As与errors.is区别在于,as会提取出调用链中指定错误类型的错误,并将其赋值给定义好的变量,方便后续处理
(而且应当尽早暴露,因为在这种情况下,服务器就算启动起来也不会有意义)
如图:消费队列启动失败使用panic,再把错误日志打出来。原因在于程序的主要功能在消费队列里,若一开始消费队列启动失败,接下来的操作也无意义。
Recover:
当我们引入的其他库中有bug导致程序本身有panic就用recover处理
Recover的生效条件:
故在写多个defer时要注意执行顺序
当前gorutine,必须在panic之后才能recover(如图)
如果需要更多的上下文信息,可以recover后在log中记录当前的调用栈 panic的上下文方便定位问题
如图:
用debug.Stack来记录调用的错误信息,堆栈信息打印出来 方便定位具体问题代码
小结:
命名方式在调用时优劣对比更明显了 1 2
最终输出 31(除了后进先出之外,前面执行了true就执行不到else)
1,3性能优化建议
应当分析时间和空间效率哪个更重要 做出合理的折中
go test-bench=,-benchmem
通过运行benchmark可以得到测试结果 -benchmem也可以统计内存信息
8:核数
可见预分配运行时间降低为1/3左右
和底层数据结构有关
切片扩容比较耗时,故在初始化预分配时需要确定容量足够
切片操作并不复制切片指向的元素
创建一个新的切片会复用原来切片的底层数组 会带来如下的问题:
上为用整个数组,下为创建一个新的slice然后只拷贝所需要的元素 用go-test测试可知后者所占的的内存要小得多
1.3.3map预分配内存
同样 将map预分配可提高性能
1.3.4字符串处理
为什么+拼接性能最差:因为生成一个新的字符串需要开辟一个新的空间,新空间的大小是原来两个字符串的大小之和。拼接第三个字符串时,再开辟一段新空间,新空间是三个字符串大小之和,以此类推。
Grow 可以看出 strings.builder性能最佳
1.3.5空结构体
空结构体,不会用到值,只是占位
1.3.6
多线程编程 计数准确 线程安全
维护原则和变量,通过加锁的方式保证数据不被影响
Atomic包的性能比加锁性能更高
只保护一个变量可以考虑用atomic包
2.性能调优实战
2.1
要用具体的测试的数据来调优
不要过早 过度优化 因为产品功能是在不断迭代的
2.2
2.2.2专门熟悉pprof工具的程序
CPU 内存 协程 阻塞对程序进行分析