高质量编程与性能调优 | 青训营笔记

56 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天


本堂课主要内容是高质量编程与性能调优实战,下面主要是我个人听课时的一些笔记

个人笔记

高质量编程

  • 什么样的代码才算“高质量”?

    • 各种边界条件是否考虑完备
    • 异常情况处理,稳定性保证
    • 易读易维护
  • 编程原则:

    • 简单性

      以最简单清晰的逻辑写代码

    • 可读性

      确保代码可以被其他阅读者理解,便于他人对代码进行维护

    • 生产力

  • 那么如何编写高质量的Go代码呢?

    • 代码格式

      使用gofmt工具,帮助将代码格式化为官方统一风格

      使用goimports,在gofmt的基础上添加了依赖包管理,可以自动增删依赖包的引用,并将依赖包按照字母顺序排序

    • 注释

      Good code has lots of comments, bad code requires lots of comments. 好的代码有很多注释,坏代码需要很多注释 ——Dave Thomas and Andrew Hunt

      • 注释应该解释代码作用,如对外提供的函数需要添加注释来描述它的功能和用途

        只有在函数的功能简单而明显时才能省略这些注释,如简单的取值和设值函数

      • 注释应该解释实现过程

        代码中的一些复杂且不明显的逻辑需要添加注释进行说明,便于理解

      • 注释应该解释代码实现原因

        这种情境下需要注释来说明这样写代码的原因,适合解释代码的外部因素,提供额外的上下文

      • 注释应该解释代码什么情况下会出错

        提醒使用者一些潜在的限制条件或者无法处理的情况

    • 变量命名规范

      缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写 例如使用ServeHTTP而不是ServeHttp 使用XMLHTTPRequest或者xmlHTTPRequest

      package命名只由小写字母组成,不包含大写字母和下划线,且不能与标准库同名

    • 控制流程

      如果两个分支中都包含return语句,则可以去除冗余的else

      优先处理错误情况/特殊情况,尽量保持正常代码路径为最小缩进

    • 错误和异常处理

      优先使用errors.New来创建匿名变量来直接表示简单错误 如果有格式化的需求,使用fmt.Errorf

      fmt.Errorf中使用: %w关键字来将一个错误关联至错误链中

      fmt.Errorf("reading srcfiles list: %w",err)

      错误判定:

      判定一个错误是否为特定错误,使用errors.Is

      不同于使用==,使用该方法可以判定错误链上的所有错误是否含有特定的错误

      在错误链上获取特定种类的错误,使用errors.As

      异常处理:

      不建议在业务代码中使用panic,因为如果调用函数不包含recover会造成程序崩溃

      若问题可以被屏蔽或解决,建议使用error代替panic

      只由当程序启动阶段发生不可逆转的错误时,才可以在init或main函数中使用panic

      recover:

      recover只能在被defer的函数中使用,嵌套无法生效,且只在当前goroutine生效

      如果需要更多的上下文信息,可以recover后在log中记录当前的调用栈

  • 性能优化建议

    • Benchmark

      Go语言自身提供的支持基准性测试的benchmark工具

      go test -bench=. -benchmem

    • Slice内存预分配

      切片的自动追加扩容会比较耗时,所以尽量在用make()初始化切片的同时提供容量信息,这样只有一次内存分配

    • Slice拷贝创建

      在已有切片基础上创建切片,不会创建新的底层数组

      在原切片较大,且需要在原切片基础上新建小切片时,可以使用Copy()代替re-slice

    • map内存预分配

    • 字符串处理

      使用strings.Builder进行字符串拼接,在拼接时不需要重新分配内存(但是+需要重新分配内存)

    • 空结构体

      空结构体struct{}实例不占据任何的内存空间

      可作为各种场景下的占位符使用

      实现set也可以用这种方法下的map代替(map的value是struct{}类型)

    • atomic包

      之前文章中提过,这里不再赘述

性能调优实战

主要是介绍了性能分析工具pprof的使用和原理,以及基于pprof,结合案例介绍了实战中如何进行性能调优

pprof是用于可视化和分析性能分析数据的工具

这里是pprof官方的document

参考