Go高质量编程简介及性能调优 | 青训营笔记

61 阅读3分钟

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

高质量编程

编码规范

  • 代码格式:推荐使用 gofmt 和 goimports 工具自动格式化代码。对于 GoLand,可以在

    Settings - Tools - Actions on Save中打开Reformat code和Optimize imports

    ,也可通过 Ctrl+Alt+L 快捷键格式化代码。

  • 注释:解释代码作用、解释代码如何做的、解释代码实现的原因、解释代码什么情况会出错;公共符号始终要注释

  • 命名规范:变量、函数、包

  • 控制流程:避免嵌套,保持正常流程清晰;尽量保持正常代码路径为最小缩进

    // Bad if foo { return x } else { return nil } ​ // Good if foo { return x } return nil

  • 错误和异常处理

  1. 对于简单错误(仅出现一次,在其他地方不需要捕获),优先使用 errors.New 创建匿名变量直接表示;如有格式化需求,使用 fmt.Errorf;

    // 一个例子 func defaultCheckRedirect(req *Request, via []*Request) error { if len(via) >= 10 { // 使用errors.New return errors.New("stopped after 10 redirects.") } return nil // 去掉不必要的else }

  2. fmt.Errorf 中使用 %w 将一个错误关联至错误链中;

    // 一个例子 list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles")) if err != nil { return fmt.Errorf("reading srcfiles list: %w", err) }

  3. 使用 errors.Is 判定一个错误为特性错误,比起直接使用 == 的好处是可以判断错误链上的所有错误是否含有特定错误;

    // 一个例子 data, err = lockedfile.Read(targ) if errors.Is(err, fs.ErrNotExist) { return []byte{}, nil } return data, err

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

    // 一个例子 if _, err := os.Open("non-existing"); err != nil { var pathError *fs.PathError if errors.As(err, &pathError) { fmt.Println("Failed at path:", pathError.Path) } else { fmt.Println(err) } }

  5. 只有在程序启动阶段发生不可逆转的错误时才使用 panic()(类似于 Java中 java.lang.Error 的地位,但是 Go 可以使用 revover() 语句来从 panic 中恢复;

性能优化建议

  • Benchmark:支持基准性能测试的工具
  • Slice, Map预分配内存
  • 大内存未释放陷阱:注意为切片创建切片不会创建新的底层数组,这可能会导致内存泄漏发生,此时可用 copy 代替 re-slice。
  • strings.Builder:在字符串拼接的过程中,使用strings.Builder往往比直接+要快。这和 Java 倒是十分相似,Java 也推荐使用 StringBuilder 拼接多个字符串;其实他们的底层逻辑都是类似的。
  • 空结构体:空结构体struct{}实例不占据任何的内存空间,利用map+struct{}创建set。
  • atomic包:cas乐观锁,使用 atomic 包代替锁修改变量。

性能调优实战

性能调优分析工具pprof

  • 采样数据说明
  1. allocs:内存分配情况
  2. blocks:阻塞操作情况
  3. cmdline:程序启动命令及
  4. goroutine:当前所有goroutine的堆栈信息
  5. heap:堆上内存使用情况(同alloc)
  6. mutex:锁竞争操作情况
  7. profile: CPU占用情况
  8. threadcreate:当前所有创建的系统线程的堆栈信息
  9. trace:程序运行跟踪信息
  • 常用指令
  1. 输入top可以查看CPU占用最高的函数,参数说明:

  2. 如果只需要查看最高的N个函数,则输入topN即可

  3. 命令list根据指定的正则表达式查找代码行,例如list Eat

  4. 命令web调用关系可视化,生成一张调用关系图,会默认使用浏览器打开,非常直观

性能调优案例

  • 业务服务优化
  • 基础库优化
  • Go语言优化