高质量编程与性能调优实战 | 青训营

84 阅读3分钟

高质量编程与性能调优实践

项目目录:(使用的编译环境为Jetbrains Golang)

image.png

运行结果:(部分)

image.png

性能优化建议

  • 简介:

1. 性能优化的前提是满足正确可靠、简洁清晰等质量因素。

2. 性能优化是综合评估,有时候 时间效率和空间效率可能对立。

3. 针对Go语言特性,介绍Go相关的性能优化建议。

  • Benchmark

1. 性能表现需要实际数据衡量。

2. Go语言提供了支持基准性能测试的benchmark 工具。

Ø 例如:

image.png

image.png

结果:

image.png

  1. BenchmarkFib10为测试函数名 -12表示GOMAXPROCS的值为12,也就是CPU核数为12。

  2. 4347187 表示一共执行1855870次,即b.N的值。

  3. 279.6 ns/op 表示每次执行花费279.6 ns/op。

  4. 每次执行申请多大的内存,每次执行申请几次内存应该都是0。

  • Slice-预分配内存

1. 尽可能在使用make()初始化切片时提供容量信息。

2. 提前指定分配内存有利于降低执行时间和分配次数。

Ø 例如:

没有提前分配内存的执行时间:

image.png

image.png

提前分配了内存的执行时间:

image.png

image.png

  • Slice的数据结构:

1. 切片本质是一个数组片段的描述,包括数组指针,片段的长度,片段的容量(不改变内存分配情况下的最大长度)。

2. 切片操作并不复制切片指向的元素。

3. 创建一个新的切片会复用原来切片的底层数组。

image.png

(由图可知上面部分的图表示提前分配内存;下面部分表示不提前分配内存时会有一个内存拷贝过程,这个过程需要时间)

(1) 若原来的切片比较大那么会出现大内存未释放的问题。

在已有切片基础上创建切片,不会创建新的底层数组。

(2) 使用场景:

原切片较大,代码在原切片基础上新建小切片。

原底层数组在内存中有引用,得不到释放可使用copy替代re-slice。

Ø 例如:

image.png

image.png

直接使用原始切片占用100.14MB,使用copy后占用3.14MB。

  • MAP

image.png

分析

1. 不断向map中添加元素的操作会触发map的扩容

2. 提前分配好空间可以减少内存拷贝和 Rehash的消耗

3. 建议根据实际需求提前预估好需要的空间

  • 字符串的处理

Ø 使用+的方式:

image.png

Ø 使用StrBuilder:

image.png

Ø 使用ByteBuffer:

image.png

结果:

image.png

结果表示:使用+拼接性能最差,strings.Builder, bytes. Buffer相近,strings. Buffer更快

  • 分析

1. 字符串在Go语言中是不可变类型,占用内存大小是固定的

2. 使用+每次都会重新分配内存

3. strings.Builder, bytes. Buffer底层都是[]byte 数组

4. 内存扩容策略,不需要每次拼接重新分配内存

5. bytes.Buffer 转化为字符串时重新申请了一块空间

6. strings.Builder直接将底层的[]byte转换成了字符串类型返回

总结

在编写代码时不仅需要保证代码的正确性,而且要使用合适的工具和方法提高程序的性能,代码的正确性和代码的可维护性是同等重要的。