Go基础学习三 | 青训营

82 阅读5分钟

go性能优化

一、高质量优化

编写的代码能够达到正确可靠、简洁清晰的目标可称之为高质量代码.

编程原则:简单性、可读性、生产力

1、编码规范

(1) 代码格式

gofmt:自动格式化代码,保证所有的Go代码与官方推荐格式保持一致。而且可以很方便的进行配置;

goimports: 会对依赖包进行管理,自动增删依赖的包引用,按字母序排序分类,具体可以根据团队实际情况配置使用;

(2)代码注释

注释应该解释代码作用;

注释应该解释代码如何做的;

注释应该解释代码实现的原因;

注释应该解释代码什么情况会出错。

(3) 命名规范

变量命名:

简洁胜于冗长;

缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写;

变量距离其被使用的地方越远,则需要携带越多的上下文信息

函数:

函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的;

函数名尽量简短;

package:

只由小写字母组成。不包含大写字母和下划线等字符

简短并包含一定的上下文信息。例如schematask

不要与标准库同名。例如不要使用sync或者strings

不使用常用变量名作为包名

使用单数而不是复数

谨慎地使用缩写

控制流程:

避免嵌套,保持正常流程清晰

尽量保持正常代码路径为最小缩进优先处理错误情况特殊情况,尽早返回或继续循环来减少嵌套

线性原理,处理逻辑尽量走直线,避免复杂的嵌套分支

正常流程代码沿着屏幕向下移动

提升代码可维护性和可读性

故障问题大多出现在复杂的条件语句和循环语句中

2 、性能优化

(1)使用Benchmark进行性能评估

(2)使用slice,make方法时要提供容量信息,预先设置容量信息,避免额外的内存分配。

在Go语言中,切片是对数组的一个连续片段的引用。切片本身并不存储任何数据,它只是描述了底层数组中的一段。切片由三个部分组成:指向底层数组的指针、切片的长度和切片的容量;在已有切片的基础上创建新的切片时,如果新切片的长度小于或等于原切片的容量,那么新切片会共享原切片的底层数组。这意味着修改新切片的元素会同时修改原切片和其他共享该底层数组的切片的对应元素。因此,如果在这种情况下没有正确释放内存,可能会导致内存泄漏的问题。

可以使用copy函数来创建一个不共享底层数组的新切片

(3)使用+拼接性能最差,strings.Builder, bytes.Buffer 相近,strings.Buffer 更快

使用+运算符进行字符串拼接是最简单的方法,但是在每次拼接时都会创建一个新的字符串对象,并且需要将原始字符串复制到新的内存位置。这种方法在拼接大量字符串时会导致大量的内存分配和复制操作,性能最差。

后两者一个主要的区别在于前者的缓冲区使用的是一个字符串切片,后者的缓冲区使用的是一个字节切片。由于Go语言的字符串是不可变的,所以使用字符串切片作为缓冲区可以避免在拼接字符串时创建并复制中间结果。相比之下,bytes.Buffer在每次拼接字节时需要将字节转为字符串,这会导致额外的内存分配和复制

(4)空结构体不包含任何字段,因此它的大小是0字节。可以通过在需要占用最小内存的地方使用空结构体来减少内存开销。

(5)在并发编程中,atomic包更常用

3、实战

五种使用pprof采集的常用性能指标 :CPU、堆内存、Goroutine、 锁竞争和阻塞

CPU:通过 pprof 工具可以采集 CPU 使用情况。这可以帮助你找出 CPU 密集型任务的热点,并识别代码中可能存在的性能问题。

堆内存:使用 pprof 工具可以收集有关堆内存使用的信息。这对于查找内存泄漏和优化内存分配非常有用。可以获取堆分配的大小、分配的对象数量、内存分配的位置等信息。

Goroutine:pprof 可以提供有关 Goroutine 的信息,比如 Goroutine 的总数、正在运行和堵塞的 Goroutine 数量等。这有助于发现 Goroutine 泄漏、过度创建 Goroutine 或 Goroutine 竞争等问题。

锁竞争:通过 pprof 的锁竞争分析来识别锁竞争问题。可以查看锁的争用情况,找出并发访问同一资源时可能导致的性能瓶颈。

阻塞:pprof 还可以提供有关阻塞调用栈的信息。这对于查找应用程序中的阻塞点以及发现可能的死锁情况非常有用。