广州网站开发设计平台,北京建网站哪家公司好,wordpress百度分享插件下载,免费网站建设资讯Go很适合用来开发高性能网络应用#xff0c;但仍然需要借助有效的工具进行性能分析#xff0c;优化代码逻辑。本文介绍了如何通过go test benchmark和pprof进行性能分析#xff0c;从而实现最优的代码效能。原文: Profiling Go Applications in the Right Way with Examples… Go很适合用来开发高性能网络应用但仍然需要借助有效的工具进行性能分析优化代码逻辑。本文介绍了如何通过go test benchmark和pprof进行性能分析从而实现最优的代码效能。原文: Profiling Go Applications in the Right Way with Examples[1] Go Gopher为A Journey With Go创作的插图作者Renee French 什么是性能分析 性能分析(Profiling) 是分析应用程序从而识别阻碍应用性能的瓶颈的基本技术有助于检测代码的哪些部分执行时间太长或消耗太多资源(如CPU和内存)。 分析方法 有三种分析方法。 Go test(包含基准测试) 基于 runtime/pprof [2]的 运行时分析 基于 net/http/pprof [3]的 Web分析 分析类型 CPU (收集应用程序CPU使用情况的数据) 堆(Heap)/内存(Memory) (收集应用程序内存使用情况的数据) Goroutine (识别创建最多Goroutine的函数) 阻塞 (识别阻塞最多的函数) 线程 (识别创建线程最多的函数) 互斥锁 (识别有最多锁竞争[4]的函数) 本文将主要关注使用上述方法进行CPU和内存分析。 1. 基准测试(Benchmarking) 我想实现著名的两数之和算法[5]这里不关注实现细节直接运行: go test -bench. -bench参数运行项目中的所有基准测试。 go test bench输出 根据上面的输出与其他方法相比TwoSumWithBruteForce是最有效的方法。别忘了结果取决于函数输入如果输入一个大数组会得到不同的结果。 如果输入go help testflag将看到许多参数及其解释比如count、benchtime等后面将解释最常用的参数。 如果要运行特定函数可以通过如下方式指定: go test -benchBenchmarkTwoSumWithBruteForce 默认情况下基准测试函数只运行一次。如果要自定义可以使用 count参数。例如, go test -bench. -count2 输出如下所示。 带count参数的基准测试输出 默认情况下Go决定每个基准测试操作的运行时间可以通过自定义 benchtime2s指定。 可以同时使用count和benchtime参数以便更好的度量基准函数。请参考How to write benchmarks in Go[6]。 示例代码请参考Github[7]。 在现实世界中函数可能既复杂又长计时毫无作用因此需要提取CPU和内存分析文件以进行进一步分析。可以输入 go test -bench. -cpuprofilecpu.prof -memprofilemem.prof 然后通过pprof[8]工具对其进行分析。 1.1 CPU分析 如果输入 go tool pprof cpu.prof 并回车就会看到pprof交互式控制台。 go tool pprof cpu.prof输出 我们来看看最主要的内容。 输入 top15查看执行期间排名前15的资源密集型函数。 (15表示显示的节点数。) 为了解释清楚假设有一个A函数。 func A() { B() // 耗时1s DO STH DIRECTLY // 耗时4s C() // 耗时6s} flat值和cum值计算为: flat值为A4, cum值为A11(1s 4s 6s) 。 如果要基于cum进行排序可以键入 top15 -cum。也可以分别使用 sortcum和 top15命令。 如果通过 top获得更详细的输出可以指定 granularity选项。例如如果设置 granularitylines将显示函数的行。 粒度为行的top15输出 得益于此我们可以识别导致性能问题的函数的特定行。 输出还显示了运行时函数和用户自定义函数。如果只想关注自己的函数可以设置 hideruntime并再次执行 top15。 带hide选项的top15 可以通过输入hide来重置。 此外可以使用 show命令。例如输入 showTwoSum 如果只关注指定节点可以使用 focus命令。例如关注 TwoSumOnePassHashTable显示为 同时带hide和focus的top输出 可以输入focus来重置。 如果需要获取该功能的详细信息可以使用 list命令。例如想获得关于 TwoSumWithTwoPassHashTable函数的详细信息输入 list TwoSumWithTwoPassHashTable list TwoSumWithTwoPassHashTable输出 如果要查看图形化的调用栈可以键入 web。 web输出 node细节 后面将提供更多关于分析图表的细节。 还可以键入 gif或 pdf以与他人共享相应格式的分析数据。 1.2 内存分析 如果输入go tool pprof mem.prof并回车 go tool pprof mem.prof输出 top10输出 注意上面提到的flat和cum是相同的东西只是测量不同的东西(CPU单位ms内存单位MB)。 list命令 list TwoSumWithBruteForce输出 web命令 web命令输出 可以使用CPU分析部分中提到的所有命令。 下面看一下另一个方法runtime/pprof。 2. 基于runtime/pprof[9]的运行时分析 基准测试对单个函数的性能很有用但不足以理解整体情况这时就需要用到runtime/pprof。 2.1 CPU分析 基准测试内置CPU和内存分析但如果需要让应用程序支持运行时CPU分析必须首先显示启用。 如果执行go run .将看到生成的cpu.prof文件可以通过基准测试部分提到的go tool pprof cpu.prof对齐进行分析。 本节将介绍我最喜欢的特性之一pprof.Labels。此特性仅适用于CPU和goroutine分析[10]。 如果要向特定函数添加一个或多个标签可以使用pprof.Do函数。 pprof.Do(ctx, pprof.Labels(label-key, label-value), func(ctx context.Context) { // 执行标签代码}) 例如, 向特定函数添加标签 在pprof交互式控制台中键入tags将显示带了有用信息的标记函数。 tags输出 可以用标签做很多事情[11]阅读Profiler labels in Go[12]可以获得更多信息。 pprof还有很棒的web界面允许我们使用各种可视化方式分析数据。 输入go tool pprof -http:6060 cpu.proflocalhost:6060将被打开。 (为了更清楚我去掉了pprof.Labels) 让我们深入探讨图形表示。 CPU分析图 节点颜色、字体大小、边缘粗细等都有不同含义参考pprof: Interpreting the Callgraph[13]获取更多细节。可视化使我们能够更容易识别和修复性能问题。 单击图中的节点可以对其进行细化我们可以根据自己的选择对可视化进行过滤。下面展示了部分内容(focus、hide等)。 Refine选项 还可以看到其他可视化选项。 View选项 上面出现了peek和source(作为list命令)因此下面将介绍火焰图(Flame Graph)[14]。火焰图提供了代码时间花费的高级视图。 火焰图 每个函数都用一个彩色矩形表示矩形的宽度与该函数花费的时间成正比。 可以访问Github[15]获取源码。 2.2 内存分析 如果需要向应用程序添加运行时内存分析必须显式启用。 可以访问Github[16]获取源码。 如果执行go run .将看到生成的mem.prof文件可以用之前基准测试部分提到的go tool pprof mem.prof对齐进行分析。 下面将介绍两个更有用的命令tree和peek。 tree显示了执行流的所有调用者和被调用者。 tree输出 从而帮助我们识别执行流并找出消耗最多内存的对象。 (不要忘记使用granularitylines它提供了更可读的格式。) 如果希望查看特定函数的执行流程可以使用 peek命令。例如 peek expensiveFunc显示如下 还可以使用pprof web界面进行内存分析。输入 go tool pprof -http:6060 mem.prof打开 localhost:6060。 内存分析图 3. 基于net/http/pprof[17]的Web分析 runtime/pprof包提供了Go程序性能分析的低级接口而net/http/pprof为分析提供了更高级的接口允许我们通过HTTP收集程序分析信息所需要做的就是: 添加net HTTP pprof 输入localhost:5555/debug/pprof就能在浏览器上看到所有可用的分析文件。如果没有使用stdlib可以查看fiber[18]、gin[19]或echo[20]的pprof实现。 debug/pprof视图 文档里记录了所有用法和参数[21]我们看一下最常用的。 获取CPU分析数据及技巧 go tool pprof http://localhost:5555/debug/pprof/profile?seconds30 在CPU分析期间请注意 runtime.mallogc → 表示可以优化小堆分配的数量。 syscall.Read或者syscall.Write → 表示应用程序在内核模式下花费了大量时间为此可以尝试I/O缓冲。 获取堆(采样活跃对象内存分配)分析数据及技巧 go tool pprof http://localhost:5555/debug/pprof/heapgo tool pprof http://localhost:5555/debug/pprof/heap?gc1 就我个人而言我喜欢用GC参数诊断问题。例如如果应用程序有内存泄漏问题可以执行以下操作: 触发GC( 浏览器访问/debug/pprof/heap?gc1) 下载堆数据 假设下载文件名为file1 等待几秒或几分钟 再次触发GC( 浏览器访问/debug/pprof/heap?gc1) 再次下载堆数据 假设下载文件名为file2 使用 diff_base [22]进行比较 go tool pprof -http:6060 -diff_base file2 file1 diff_base输出 获取内存分配(抽样过去所有的内存分配)分析数据及技巧 go tool pprof http://localhost:5555/debug/pprof/allocs 在内存分配分析期间可以这样做 如果看到 bytes.growSlice应该考虑使用 sync.Pool。 如果看到自定义函数请检查是否在切片或映射中定义了固定容量。 延伸阅读 pprof Github Readme [23] Profiling Go Programs by Russ Cox [24] pprof man page [25] GopherCon 2019: Dave Cheney — Two Go Programs, Three Different Profiling Techniques [26] GopherCon 2021: Felix Geisendörfer — Go Profiling and Observability from Scratch [27] GopherConAU 2019 — Alexander Else — Profiling a go service in production [28] Practical Go Lessons Profiling Chapter [29] 你好我是俞凡在Motorola做过研发现在在Mavenir做技术工作对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣平时喜欢阅读、思考相信持续学习、终身成长欢迎一起交流学习。为了方便大家以后能第一时间看到文章请朋友们关注公众号DeepNoMind并设个星标吧如果能一键三连(转发、点赞、在看)则能给我带来更多的支持和动力激励我持续写下去和大家共同成长进步 参考资料 [1] Profiling Go Applications in the Right Way with Examples: https://blog.stackademic.com/profiling-go-applications-in-the-right-way-with-examples-e784526e9481 [2] runtime/pprof: https://pkg.go.dev/runtime/pprof [3] net/http/pprof: https://pkg.go.dev/net/http/pprof [4] Resource Contention: https://en.wikipedia.org/wiki/Resource_contention [5] Two Sum Algorithm: https://leetcode.com/problems/two-sum [6] How to write benchmarks in Go: https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go [7] pprof-example: https://github.com/Abdulsametileri/pprof-examples/tree/main/benchmarking [8] pprof: https://linux.die.net/man/1/pprof [9] runtime/pprof: https://pkg.go.dev/runtime/pprof [10] pprof.Labels: https://pkg.go.dev/runtime/pprof#Labels [11] pprof tags: https://github.com/google/pprof/blob/main/doc/README.md#tags [12] Profiler labels in Go: https://rakyll.org/profiler-labels [13] pprof: Interpreting the Callgraph: https://github.com/google/pprof/blob/main/doc/README.md#interpreting-the-callgraph [14] 火焰图(Flame Graph): https://github.com/google/pprof/blob/main/doc/README.md#flame-graph [15] runtime pprof cpu example: https://github.com/Abdulsametileri/pprof-examples/tree/main/runtimepprof/cpu [16] runtime pprof memory example: https://github.com/Abdulsametileri/pprof-examples/tree/main/runtimepprof/mem [17] net/http/pprof: https://pkg.go.dev/net/http/pprof [18] fiber pprof: https://docs.gofiber.io/api/middleware/pprof [19] gin pprof: https://github.com/gin-contrib/pprof [20] echo pprof: https://pkg.go.dev/github.com/labstack/echo-contrib/pprof [21] net/http/pprof usage examples: https://pkg.go.dev/net/http/pprof#hdr-Usage_examples [22] pprof comparing profiles: https://github.com/google/pprof/blob/main/doc/README.md#comparing-profiles [23] pprof Github Readme: https://github.com/google/pprof/blob/main/doc/README.md [24] Profiling Go Programs by Russ Cox: https://blog.golang.org/2011/06/profiling-go-programs.html [25] pprof man page: https://linux.die.net/man/1/pprof [26] GopherCon 2019: Dave Cheney — Two Go Programs, Three Different Profiling Techniques: https://www.youtube.com/watch?vnok0aYiGiYA [27] GopherCon 2021: Felix Geisendörfer — Go Profiling and Observability from Scratch: https://www.youtube.com/watch?v7hg4T2Qqowk [28] GopherConAU 2019 — Alexander Else — Profiling a go service in production: https://www.youtube.com/watch?v19bxBMPOlyA [29] Practical Go Lessons Profiling Chapter: https://www.practical-go-lessons.com/chap-36-program-profiling 本文由 mdnice 多平台发布