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

45 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。

  1. 高质量编程

    • 高质量编程简介
    • 编码规范
      • 代码格式

        • gofmt,能自动格式化Go代码为官方统一的风格。
        • goimports,等于gofmt加上依赖包管理,自动增删依赖的包引用、将依赖包按字母排序分类。
      • 注释

        • 代码是最好的注释
        • 注释应该提供代码未表达出的上下文信息
      • 命名规范(核心:降低阅读理解代码的成本)

        • variable

          • 缩略词全大写,但当其位于开头且不需要导出时,使用全小写

            • Eg:使用ServeHTTP而不是ServeHttp
            • Eg:使用XMLHTTPRequest或者xmlHTTPRequest
          • 变量距离其被使用的地方越远,则需要携带越多的上下文信息

            • 全局变量在其名字中需要更多的上下文信息,使得在不同地方可以轻易辨认
        • function

          • 函数名不携带包名的上下文信息,因为包名和函数名总是成对出现
          • 当名为foo的包某个函数返回类型Foo时,可以省略类型信息而不导致歧义
          • 当名为foo的包某个函数返回类型T时(T并不是Foo),可以在函数名中加入类型信息
        • package

          • 只由小写字母组成。不包含大写字母和下划线等字符
          • 简短并包含一定的上下文信息。
          • 不要与标准库同名。
      • 控制流程

        • 避免嵌套,保持正常流程清晰
        • 尽量保证正常代码路径为最小缩进
        • 线性原理,处理逻辑尽量走直线,避免复杂的嵌套分支
        • 正常流程代码沿着屏幕向下移动
        • 提升代码可维护性和可读性
        • 故障问题大多出现在复杂的条件语句和循环语句中
      • 错误和异常处理

        • error尽可能提供简明的上下文信息链,方便定位问题

          1. 简单错误
            1.png
          2. 错误的wrap和unwrap
            2.png
          3. error.Is
            3.png
          4. error.As 4.png
  • panic用于真正异常的情况 5.png

  • recover生效范围,在当前goroutine的被defer的函数中生效

6.png

-   ##### 性能优化建议

    -   Map:预分配内存

    -   Slice

    -   String.Builder:字符串处理

    -   空结构体用来节省内存

    -   atomic包

7.png

    -   Benchmark(以斐波那契数列举例)

        -   如果你想要了解一下详情的话,可以参考下面的连接。

            <https://www.cnblogs.com/yahuian/p/go-benchmark.html>

            <https://geektutu.com/post/hpg-benchmark.html>

        -   新建一个fib.go

            ```
            package main
            ​
            func fib(n int) int {
                if n == 0 || n == 1 {
                    return n
                }
                return fib(n-2) + fib(n-1)
            }
            package main
            ​
            import "testing"
            ​
            func BenchmarkFib(b *testing.B) {
                for n := 0; n < b.N; n++ {
                    fib(30) // run fib(30) b.N times
                }
            }
            ```

        -   再新建一个fib_test.go

            ```
            package main
            ​
            import "testing"
            ​
            func BenchmarkFib(b *testing.B) {
                for n := 0; n < b.N; n++ {
                    fib(30) // run fib(30) b.N times
                }
            }
            ```

            终端中输入

            ```
            go test -bench .
            ```

0. #### 性能调优实战

-   ##### 性能调优简介

-   ##### 性能分析工具pprof实战

    -   ##### pprof-排查实战

        ##### 如果你想了解pprof详情信息,可以参考该网站(<https://blog.wolfogre.com/posts/go-ppof-practice/>)可以解决你很多的疑问。

        -   图形化显示栈的信息,我们需要下载 graphviz (<https://blog.csdn.net/lizzy05/article/details/88529483>        -   pprof-排查实战

            -   CPU
            -   ```
                go tool pprof http://localhost:6060/debug/pprof/profile
                ```
            -   ```
                go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile
                ```
            -   Heap-内存
            -   ```
                go tool pprof -http=:8080 http://localhost:6060/debug/pprof/heap
                ```
            -   goroutine-协程
            -   ```
                go tool pprof -http=:8080 http://localhost:6060/debug/pprof/goroutine
                ```
            -   mutex-锁
            -   ```
                go tool pprof -http=:8080 http://localhost:6060/debug/pprof/mutex
                ```
            -   block-阻塞
            -   ```
                go tool pprof -http=:8080 http://localhost:6060/debug/pprof/block
                ```

    -   pprof-采样过程和原理

        -   CPU              

8.png - Heap 9.png - Goroutine-协程 ThreadCreate-协程
10.png - block-阻塞和metux-锁 11.png

-   ##### 性能调优案例