性能调优笔记总结 | 青训营

65 阅读3分钟

Go语言性能优化笔记

简介: 在软件开发中,性能优化是一个持续的追求。对于Go语言来说,该语言本身设计上已经很注重性能,但通过一些技巧和最佳实践,我们仍然可以进一步提高代码的性能。

Benchmark: 使用Go的内置测试工具,我们可以编写基准测试来衡量函数或代码段的性能。基准测试通常以Benchmark开头,并使用b *testing.B作为唯一参数。

slice预分配内存: 预分配内存可以避免多次动态扩展,提高性能。使用make函数预分配slice的容量是个好习惯。

data := make([]int, 0, 100) // 预分配容量为100的slice

map预分配内存: 与slice类似,预分配map的容量可以提高其插入操作的性能。

m := make(map[string]int, 100) // 预分配容量为100的map

strings.Builderstrings.Builder是一个高效的字符串构建工具,特别是当我们需要连接多个字符串时。

var builder strings.Builder
builder.WriteString("Hello, ")
builder.WriteString("World!")
result := builder.String()

空结构体: 在Go中,空结构体struct{}不占用任何空间。它是集合或通道中标记值的有用工具,无需额外的内存开销。

set := make(map[string]struct{})
set["item"] = struct{}{}

atomic包: 当涉及到并发访问或修改共享资源时,sync/atomic包提供了原子操作,避免了复杂的锁机制。

var counter int32
atomic.AddInt32(&counter, 1) // 原子地增加counter的值

pprof性能剖析

pprof 是 Go 提供的一个性能剖析工具,它可以生成多种类型的报告以帮助我们理解程序的行为。这些报告有助于定位代码中的性能瓶颈,从 CPU 使用、内存分配到锁的竞争等多个方面。

核心报告类型

  1. CPU Profile:显示程序的 CPU 使用情况。这可以帮助我们找到程序中耗费 CPU 时间最多的部分。
  2. Memory Profile:显示关于程序的内存分配情况的信息。这不仅可以帮助我们找到内存泄漏,还可以优化内存使用。
  3. Block Profile:显示关于 goroutines 被同步原语(如互斥锁)阻塞的情况。这有助于找到并发编程中的瓶颈。
  4. Mutex Profile:显示了关于互斥锁的竞争情况,帮助我们了解锁的竞争是否影响到程序的性能。

使用 topN 查看报告

当我们使用 pprof 的 Web 界面或命令行工具时,topN 命令是最常用的一个命令。这个命令可以列出消耗最多资源的前N项。例如,如果我们想看 CPU 使用最高的前10个函数,我们可以使用以下命令:

(pprof) top10

这将会列出前10个耗费 CPU 最多的函数,以及它们的样本数、样本百分比以及累积百分比。同样的,如果我们想看内存分配最多的前10个位置,只需加载内存剖析文件然后执行相同的 top10 命令。

除了默认的数量排序外,我们还可以使用 -cum 标志按累积数量排序,这有助于快速发现那些由多个小的分配累加起来导致的大量分配。

总结:

性能优化是一门艺术,需要细致的关注和实践。Go提供了一系列的工具和技巧帮助我们优化代码性能。从预分配内存,使用高效的字符串连接方法,到并发的原子操作和性能剖析,每一个细节都可能影响到应用的整体性能。在开发过程中,充分利用这些工具和最佳实践,可以帮助我们构建更高效、更可靠的Go应用。