这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记
我讲从以下几个方面:高质量编程 性能优化
高质量编程
- 原则:间接性 可读性 生产力(团队合作效率)
- 规范
- 代码格式:gofmt
- 注释:代码作用、代码如何做、实现原因、代码限制条件、公共符号一定要注释
- 命名:根据需要的信息量、大小写、缩写
- 控制流程:实现最小缩进
- 错误和异常处理:
- 简单错误
errors.New - 复杂错误
fmt.Errorf - 错误判定
errors.As - panic(少用)
- recover(当前goroutine被defer函数中生效)
- 简单错误
func defaultCheckRedirect(req *Request, via []*Request) error{
if len(via) >= 10{
return errors.New("stopped after 10 redirects")
}
return nil
}
list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles"))
if err != nil{
return fmt.Errorf("reading srcfiles list: %w", err)
}
性能优化
- 工具:
benchmark go test -bench=. -benchmem- 函数名 被执行次数 每次执行时间 执行申请内存大小 每次执行申请内存次数
- 建议:
-
Slice 和 Map 预分配
-
字符串拼接:使用strings.Builder >(内存)> bytes.Buffer > (重新内存分配)"+"
2.1. +法:右边的值会引起内存分配
2.2. Bytes.Buffer: bytes包处理方式是再次进行一次切片处理
2.3. Strings.Builder: Strings包是直接指针转换
举例说明:
-
s := "aa"
for i:=0; i<size; i++{
s +="ccc"
}
var s bytes.Buffer
for i:=0; i<10; i++{
s.WriteString("cc")
}
s.String();
var s strings.Builder
for i:=0; i<size; i++{
s.WriteString("cc")
}
s.String()
-
使用空结构体struct{} 不占用空间-是作为map实现set的不错的工具(这里面我们只需要用map键,而非它的值) 如果用map的值设为了bool也会多占用1个字节空间。因此强推使用空结构体,省空间
-
atomic包 下面我们比较atomic保护变量的并发安全和sync.Mutex保护的并发安全效果 使用atomic包示例;
type atomicCounter struct{
i int32
}
func AtomicAddOne(c*atomicCounter){
atomic.AddInt32(&c.i,1)
}
type mutexCounter struct{
i int32
m sync.Mutex
}
func MutexAddOne(c *mutexCounter){
c.m.Lock()
c.i++
c.m.Unlock()
}
结果: