这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记
高质量编程
判定标准
- 各种边界条件是否考虑完备。
- 对于异常情况处理是否完备(稳定性保证)。
- 易读易维护。
编程规范
编程规范所要考虑的范围
-
代码格式。可以通过
gofmt和goimports自动格式化代码。gofmt能自动格式化GO语言代码为官方统一风格;goimports实质上是再gofmt基础上加上对依赖包的管理,自动增删依赖的包引用,将依赖包按字母序排序分类。 -
注释。注释使用场景:
- 公共符号使用注释。
- 注释实现过程。
- 注释代码实现原理。
- 注释出错条件。
-
命名规范。
-
对于变量的命名规范:1.简洁;2.缩略词全大写,当其处于变量开头且不需要导出时,使用全小写(如
XMLHTTPRequest/xmlHTTPRequest);3. 变量距离使用的地方越远,需要携带上下文信息越多。 -
对于函数名的命名规范:1. 不携带包名的上下文信息。; 2. 简洁;
3.当包名与返回值类型一致时,可以省略类型信息
-
-
控制流程。 线性原理,尽量避免复杂嵌套。
-
错误和异常处理。 GO处理错误/异常的方式不同于Java,Java会在异常处直接抛出异常产生的栈信息,而GO采用控制流的方式处理异常信息,通过函数的返回值返回
error信息。当然,GO也可以通过异常嵌套的方式生成错误链,这样也可以在每一层异常中嵌套入当前的上下文信息,,error尽可能提供简洁的上下文信息链,方便定位问题。
性能调优
使用benchmark工具观察程序执行情况
下列以斐波那契函数为例进行分析
从左到右依次为:测试函数名 , b.N的值(即执行次数),每次执行花费的时间(ns/op),每次执行申请的内存空间(B/op) 每次执行申请内存次数(allocs/op)
性能调优建议
- 使用slice预分配内存。 创建
slice可以通过make(Type,length)和make(Type,length,cap)创建,当slice增加的时候,由于slice本身结构的原因,会新分配一个大小为加入slice之的空间到原slice的后方,而如果创建时先预分配了内存空间,则会将加入的切片直接放在slice的后续空间当中。 - 大内存未释放问题。 当从一个大的
slice中切片出一个小内存时,由于小内存对原slice有引用,所以原先的大内存不会释放,在这种情况下需要用copy替代re-slice - 字符串处理。 使用“+”拼接性能最差,strings.Builder,bytes.Buffer相近,strings.Buffer更快.
- 使用空结构体。 空结构体不占空间,仅作为占位符,如如果
map[type]struct{}来实现set - 使用atomic包。
atomic包实现原子性的功能由操作系统提供,会降低自己实现原子性的开销。