这是我参与「第五届青训营 」笔记创作活动的第3天
本篇文章主要讲述在编程过程中需要注意的相关规则,并通过主要的实战例子进行讲解。 主要分为两块:高质量编程、性能调优实战
1.高质量编程
所谓高质量编程,即:编写的代码能够达到正确可靠、简洁清晰的目标可称之为高质量代码。
1.1 编码原则介绍
简单性:
消除“多余的复杂性”,以简单清晰的逻辑编写代码。
不理解的代码无法修复改进。
可读性:
代码是写给人看的,而不是机器。
编写可维护代码的第一步是确保代码可读性。
生产力
团队整体工作效率非常重要。
1.2 编码规范
该节主要介绍在编写代码过程中我们需要如何将代码写的更加规范,方便后续编程人员的理解和解读。因此,将主要从以下五个方面进行介绍。
1.2.1 代码格式
- 第一种格式为:gofmt
该格式是Go语言官方提供的工具,能够自动格式化Go语言代码为官方统一风格。
- 第二种方式为:goimport
该格式也为Go语言官方提供的工具,实际等于gofmt加上依赖包管理,可以自动增删依赖的包引用、将依赖包按字母序排序并分类。
1.2.2 注释
1、注释需要适合公共符号
2、注释在代码编写的过程中需要简洁且适合实现过程
3、注释可以解释代码的外部因素,并提供额外的上下文,方便读者进行理解
4、注释要适合代码的限制条件
5、注释过程中需要将公共符号进行注释,如:
-
包中声明的每个公共的符号:变量、常量、函数以及结构都需要添加注释;
-
任何既不明显也不简短的公共功能必须予以注释,对于具体的例子,如;LimitedReader.Read本身没有注释,但它紧跟LimitedReader结构的声明,明确它的作用;
-
无论代码的长度或复杂度如何,对库中的任何函数都必须进行注释
1.2.3 命名规范
- 对于简单的语句中,代码命名的小规则:
i和index作用在for循环中时,可以直接用i进行命名,因为index的额外冗长几乎不会增加对程序的进一步理解。
- 对于具体的函数的命名,需要注意的小规则:
函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的
函数名尽量简短
当名为foo的包某个函数返回类型Foo时,可以省略类型信息而不导致歧义
当名为foo的包某个函数返回类型T时(T并不是Foo),可以在函数名中加入类型信息
- 对于具体的包的命名,需要注意的小规则:
-
只有小写字母组成,不包含大写字母和下划线等字符
-
简短并包含一定的上下文信息,例如schema、task等
-
不要与标准库同名,例如不要使用sync或者sttings
-
不使用常用变量名作为包名,例如使用bufio而不是buf
-
使用单数而不是复数,例如使用encoding而不是encodings
-
谨慎使用缩写,例如使用fmt在不破坏上下文的情况下比format更加简短
1.2.4 控制流程
1、在嵌套语句中,若两个分支中都包含return语句,则可以去除冗余的else,即:避免嵌套,保持正常流程清晰
2、优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套,即:尽量保持正常代码路径为最小缩进
注意:故障问题大多出现在复杂的条件语句和循环语句中
1.2.5 错误和异常处理
-
error尽可能提供简明的上下文信息链,方便定位问题
-
panic用于真正异常的情况
-
recover生效范围,在当前goroutine的被defer的函数中生效
1.3 性能优化建议
本节主要对常见的几个需要进行优化的问题进行阐述,提出相应的优化改进建议。
1.3.1 切片
切片本质是一个数组片段的描述,包括数组指针,片段的长度,片段的容量,切片操作并不复制切片指向的元素,创建一个新的切片会复用原来切片的底层数组
注意:当大内存未释放时,若已有切片,则不会创建一个新的底层数组。可以使用copy替代re-slice。
1.3.2 Map
Map预分配内存,需要不断向map中添加元素的操作会触发map扩容,提前分配好空间可以减少内存拷贝和Rehash的消耗,建议根据实际需求提前预估好需要的空间。
2.性能调优实战
2.1 简单介绍
在性能调优实际排查项目中,主要用到的工具是PProf.
这里主要用到的项目代码如下:
import {
"log"
"net/http"
_"net/http/pprof"
}
func main(){
log.SetFlags(log.Lshortfile | log.LstdFlags)
log.SetOutput(os.Stdout)
runtime.GOMAXPROCS(1)
runtime.SetMutexProfileFraction(1)
runtime.SetBlockProfileRate(1)
go func() {
if err := http.ListenAndServe(":6060",nil); err != nil {
log.Fatal(err)
}
os.Exit(0)
}()
}
对系统的调优主要从CPU、Heap-堆内存、Goroutine-协程和ThreadCreate-线创建、Block-阻塞和Mutex-锁等方面进行操作。
2.2 业务服务优化
基本概念
-
服务:能单独部署,承载一定功能的程序
-
依赖:Service A的功能实现依赖Service B的响应结果,称为Service A依赖Service B
-
调用链路:能支持一个接口请求的相关服务集合及其相互之间的依赖关系
-
基础库:公共的工具包、中间件
流程
-
建立服务性能评估手段
-
分析性能数据,定位性能瓶颈
-
重点优化项改造
-
优化效果验证
总结
通过本次课程的学习,我了解了编程过程中需要注意的相关规则,也对自己今后写代码有了一定的约束和参考。同时还了解到关于在工作中,即实际项目中,我们需要对代码进行优化,不仅可以提高代码的运行速度,同时能够减少内存的存储。当然,在程序方面自己还有很大的不足,需要不断改进和提升。
引用
本文的内容来自于字节内部课程。