Go语言后端 | 青训营笔记

53 阅读3分钟

这是我参与[第五届青训营]办学笔记创作活动的第3天。这节课主要在学习高质量编程与性能调优实战。

  1. 本节课重点内容

    本节课主要介绍两个部分的内容:第一部分是高质量编程,主要从高质量编程简洁、编码规范核性能优化建议三个方面展开;第二部分是性能调优实战,主要分为性能调优简介、性能分析工具pprof实战、性能调优案例三个方面。

  2. 详细知识点介绍

  • 高质量编程 主要遵循的编程原则:简单性、可读性、生产力。简单性主要是指消除“多余的复杂性”,以简单清晰的逻辑编写代码;编写可维护代码的第一步是确保代码可读;生产力主要关注团队整体的工作效率。

    编码规范————注释。公共符号始终要注释,包中声明的每个公共的符号:变量、常量、函数以及结构都需要添加注释;任何既不明显也不简短的公共功能必须予以注释;无论长度或复杂程度如何,对库中的任何函数都必须进行注释。推荐使用gofmt自动格式化代码(gofmt、goimports)

    编码规范————控制流程。尽量保持正常代码路径为最小缩进,优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套。

    编码规范————错误和异常处理。简单错误:指仅出现一次的错误,且在其他地方不不需要捕获该错误;优先使用errors.New来创建匿名变量来直接表示简单错误,如果有格式化的需求,使用fmt.Errorf。错误的Wrap和Unwrap:错误的Wrap实际上是提供了一个error嵌套另一个error的能力,从而生成一个error的跟踪链,在fmt.Errorf中使用%w关键字将一个错误关联至错误链中。判定一个错误是否为特定错误,使用errors.Is,该方法可以判定错误链上的所有错误是否含有特定的错误。在错误链上获取特定种类的错误,使用errors.As。

    小结:error尽可能提供简明的上下文信息链,方便定位问题;panic用于真正异常的情况;recover生效范围,在当前goroutine的被defer的函数中生效。 1.png

  • 性能优化建议

    benchmark:性能表现需要实际数据衡量,Go语言提供了支持基准性能测试的benchmark工具,可调用语句"go test -bench=. -benchmem"实现。

    slice:预分配内存,尽可能使用make()初始化切片时提供容量信息,预先分配内存信息可以有效提高代码运行效率。切片本质是一个数组片段的描述,是一个struct结构体,包括数组指针、片段的长度、片段的容量。

    map:预分配内存,不断向map中添加元素的操作会触发map的扩容,提前分配好空间可以减少内存拷贝和Rehash的消耗。

    字符串处理:使用+拼接性能最差,使用strings.Builder比strings.Buffer效果更好;字符串在Go语言中是不可变类型,占用内存大小是固定的,使用+每次都会重新分配内存,string.Builder和strings.Buffer底层都是byte数组,有相应的内存扩容策略,不需要每次拼接重新分配内存,因此效率更高。

    使用空结构体节省内存:空结构体struct{}实例不占据任何的内存空间,可作为占位符使用。

    多线程:atomic包(效率更高)、加锁机制

  • 性能分析工具pprof 1.png