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

110 阅读3分钟

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

编码规范

代码格式

可以使用gofmt自动格式化代码
gofmt在goland IDE中可以进行配置
settings中搜索file watcher

image.png 选择go fmt

image.pngarguments参数栏添加-x参数后,apply即可
go fmtgofmt的一层封装,go fmt = gofmt -l -w

注释

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

代码是最好的注释

注释应该提供代码未表达出的上下文信息

命名规范

变量

  • 简洁胜于冗长
  • 缩略词全大写,位于变量开头,且不导出,全小写
  • 变量距离使用地方越远,需要携带更多上下文信息

函数

  • 函数名不需要携带包名的上下文信息
  • 函数名尽量简短
  • 名为foo的包某个函数返回类型Foo时,可省略类型信息而不导致歧义
  • 名为foo的包某个函数返回类型T时,可以在函数名中加入类型信息

package

  • 小写字母,不使用大写字母、下划线
  • 包含一定上下文信息
  • 不与标准库同名
  • 不使用常用变量名作为包名
  • 单数不是复数
  • 谨慎使用缩写

控制流程

  • 避免复杂的嵌套
  • 优先处理错误或特殊情况,尽早返回或继续循环减少嵌套

错误和异常处理

  • 简单错误 使用errors.New 创建匿名变量,使用fmt.Errorf格式化错误
  • 复杂错误 fmt.Errorf %w 打印错误调用链
  • panic 不建议业务代码中使用,调用函数不包含recover会直接崩溃,在初始化时出现不可逆错误可以使用panic直接结束
  • recover只能在defer中使用

性能优化

切片及映射

s := make([]int, 0, 10)
m := make(map[string]int, 8)

切片及映射在初始化时建议初始化容量,可以避免频繁扩容对程序性能产生影响

字符串拼接

下面将使用benchmark test去分析字符串拼接时各个处理方式的性能

func BenchmarkStringAdd(b *testing.B) {
   for i := 0; i < b.N; i++ {
      //StringAdd(s1, s2)
      MultiStringAdd(s1)
   }
}

func BenchmarkStringBuilder(b *testing.B) {
   for i := 0; i < b.N; i++ {
      //ByStringBuilder(s1, s2)
      MultiByStringBuilder(s1)
   }
}

func BenchmarkBytesBuffer(b *testing.B) {
   for i := 0; i < b.N; i++ {
      //ByBytesBuffer(s1, s2)
      MultiByBytesBuffer(s1)
   }
}

func StringAdd(a, b string) string {
   return a + b
}

func ByStringBuilder(a, b string) string {
   sb := strings.Builder{}
   sb.WriteString(a)
   sb.WriteString(b)

   return sb.String()
}

func ByBytesBuffer(a, b string) string {
   buf := bytes.NewBuffer(nil)
   buf.WriteString(a)
   buf.WriteString(b)
   return buf.String()
}

func MultiStringAdd(a string) string {
   s := ""
   for i := 0; i < 100; i++ {
      s += a
   }
   return s
}

func MultiByStringBuilder(a string) string {
   sb := strings.Builder{}
   for i := 0; i < 100; i++ {
      sb.WriteString(a)
   }

   return sb.String()
}

func MultiByBytesBuffer(a string) string {
   buf := bytes.NewBuffer(nil)
   for i := 0; i < 100; i++ {
      buf.WriteString(a)
   }

   return buf.String()
}

当仅有两个字符串进行拼接时,string operation add的效率明显优于stringBuilder及BytesBuffer image.png 当多次字符串拼接时,string operation add的效率下降明显,需要频繁申请内存分配,stringBuilder的底层为byte数组,每次扩容都会扩为原先的2倍,减小了扩容次数 image.png 总结: 在小数据量时,优先选用+拼接,在大数据量时选用stringBuilder或BytesBuffer性能差别不大