更新、更全的《Go从入门到放弃》的更新网站,更有python、go、人工智能教学等着你:https://www.cnblogs.com/nickchen121/p/11517502.html

在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况。
Go语言是一个对性能特别看重的语言,因此语言中自带了 profiling 的库,这篇文章就要讲解怎么在 golang 中做 profiling。

一、Go性能优化

Go语言项目中的性能优化主要有以下几个方面:

  • CPU profile:报告程序的 CPU 使用情况,按照一定频率去采集应用程序在 CPU 和寄存器上面的数据
  • Memory Profile(Heap Profile):报告程序的内存使用情况
  • Block Profiling:报告 goroutines 不在运行状态的情况,可以用来分析和查找死锁等性能瓶颈
  • Goroutine Profiling:报告 goroutines 的使用情况,有哪些 goroutine,它们的调用关系是怎样的

二、采集性能数据

Go语言内置了获取程序的运行数据的工具,包括以下两个标准库:

  • runtime/pprof:采集工具型应用运行数据进行分析
  • net/http/pprof:采集服务型应用运行时数据进行分析

pprof开启后,每隔一段时间(10ms)就会收集下当前的堆栈信息,获取格格函数占用的CPU以及内存资源;最后通过对这些采样数据进行分析,形成一个性能分析报告。

注意,我们只应该在性能测试的时候才在代码中引入pprof。

三、工具型应用

如果你的应用程序是运行一段时间就结束退出类型。那么最好的办法是在应用退出的时候把 profiling 的报告保存到文件中,进行分析。对于这种情况,可以使用runtime/pprof库。
首先在代码中导入runtime/pprof工具:

import "runtime/pprof"

3.1 CPU性能分析

开启CPU性能分析:

pprof.StartCPUProfile(w io.Writer)

停止CPU性能分析:

pprof.StopCPUProfile()

应用执行结束后,就会生成一个文件,保存了我们的 CPU profiling 数据。得到采样数据之后,使用go tool pprof工具进行CPU性能分析。

3.2 内存性能优化

记录程序的堆栈信息

pprof.WriteHeapProfile(w io.Writer)

得到采样数据之后,使用go tool pprof工具进行内存性能分析。

go tool pprof默认是使用-inuse_space进行统计,还可以使用-inuse-objects查看分配对象的数量。

四、服务型应用

如果你的应用程序是一直运行的,比如 web 应用,那么可以使用net/http/pprof库,它能够在提供 HTTP 服务进行分析。

如果使用了默认的http.DefaultServeMux(通常是代码直接使用 http.ListenAndServe(“0.0.0.0:8000”, nil)),只需要在你的web server端代码中按如下方式导入net/http/pprof

import _ "net/http/pprof"

如果你使用自定义的 Mux,则需要手动注册一些路由规则:

r.HandleFunc("/debug/pprof/", pprof.Index)
r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/debug/pprof/profile", pprof.Profile)
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
r.HandleFunc("/debug/pprof/trace", pprof.Trace)

如果你使用的是gin框架,那么推荐使用"github.com/DeanThompson/ginpprof"

不管哪种方式,你的 HTTP 服务都会多出/debug/pprof endpoint,访问它会得到类似下面的内容:

这个路径下还有几个子页面:

  • /debug/pprof/profile:访问这个链接会自动进行 CPU profiling,持续 30s,并生成一个文件供下载
  • /debug/pprof/heap: Memory Profiling 的路径,访问这个链接会得到一个内存 Profiling 结果的文件
  • /debug/pprof/block:block Profiling 的路径
  • /debug/pprof/goroutines:运行的 goroutines 列表,以及调用关系

五、go tool pprof命令

不管是工具型应用还是服务型应用,我们使用相应的pprof库获取数据之后,下一步的都要对这些数据进行分析,我们可以使用go tool pprof命令行工具。

go tool pprof最简单的使用方式为:

go tool pprof [binary] [source]

其中:

  • binary 是应用的二进制文件,用来解析各种符号;
  • source 表示 profile 数据的来源,可以是本地的文件,也可以是 http 地址。

注意事项:
获取的 Profiling 数据是动态的,要想获得有效的数据,请保证应用处于较大的负载(比如正在生成中运行的服务,或者通过其他工具模拟访问压力)。否则如果应用处于空闲状态,得到的结果可能没有任何意义。

六、具体示例

首先我们来写一段有问题的代码:

// runtime_pprof/main.go
package main import (
"flag"
"fmt"
"os"
"runtime/pprof"
"time"
) // 一段有问题的代码
func logicCode() {
var c chan int
for {
select {
case v := <-c:
fmt.Printf("recv from chan, value:%v\n", v)
default: }
}
} func main() {
var isCPUPprof bool
var isMemPprof bool flag.BoolVar(&isCPUPprof, "cpu", false, "turn cpu pprof on")
flag.BoolVar(&isMemPprof, "mem", false, "turn mem pprof on")
flag.Parse() if isCPUPprof {
file, err := os.Create("./cpu.pprof")
if err != nil {
fmt.Printf("create cpu pprof failed, err:%v\n", err)
return
}
pprof.StartCPUProfile(file)
defer pprof.StopCPUProfile()
}
for i := 0; i < 8; i++ {
go logicCode()
}
time.Sleep(20 * time.Second)
if isMemPprof {
file, err := os.Create("./mem.pprof")
if err != nil {
fmt.Printf("create mem pprof failed, err:%v\n", err)
return
}
pprof.WriteHeapProfile(file)
file.Close()
}
}

通过flag我们可以在命令行控制是否开启CPU和Mem的性能分析。
将上面的代码保存并编译成runtime_pprof可执行文件,执行时加上-cpu命令行参数如下:

./runtime_pprof -cpu

等待30秒后会在当前目录下生成一个cpu.pprof文件。

6.1 命令行交互界面

我们使用go工具链里的pprof来分析一下。

go tool pprof cpu.pprof

执行上面的代码会进入交互界面如下:

runtime_pprof $ go tool pprof cpu.pprof
Type: cpu
Time: Jun 28, 2019 at 11:28am (CST)
Duration: 20.13s, Total samples = 1.91mins (568.60%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

我们可以在交互界面输入top3来查看程序中占用CPU前3位的函数:

(pprof) top3
Showing nodes accounting for 100.37s, 87.68% of 114.47s total
Dropped 17 nodes (cum <= 0.57s)
Showing top 3 nodes out of 4
flat flat% sum% cum cum%
42.52s 37.15% 37.15% 91.73s 80.13% runtime.selectnbrecv
35.21s 30.76% 67.90% 39.49s 34.50% runtime.chanrecv
22.64s 19.78% 87.68% 114.37s 99.91% main.logicCode

其中:

  • flat:当前函数占用CPU的耗时
  • flat::当前函数占用CPU的耗时百分比
  • sun%:函数占用CPU的耗时累计百分比
  • cum:当前函数加上调用当前函数的函数占用CPU的总耗时
  • cum%:当前函数加上调用当前函数的函数占用CPU的总耗时百分比
  • 最后一列:函数名称

在大多数的情况下,我们可以通过分析这五列得出一个应用程序的运行情况,并对程序进行优化。

我们还可以使用list 函数名命令查看具体的函数分析,例如执行list logicCode查看我们编写的函数的详细分析。

(pprof) list logicCode
Total: 1.91mins
ROUTINE ================ main.logicCode in .../runtime_pprof/main.go
22.64s 1.91mins (flat, cum) 99.91% of Total
. . 12:func logicCode() {
. . 13: var c chan int
. . 14: for {
. . 15: select {
. . 16: case v := <-c:
22.64s 1.91mins 17: fmt.Printf("recv from chan, value:%v\n", v)
. . 18: default:
. . 19:
. . 20: }
. . 21: }
. . 22:}

通过分析发现大部分CPU资源被17行占用,我们分析出select语句中的default没有内容会导致上面的case v:=<-c:一直执行。我们在default分支添加一行time.Sleep(time.Second)即可。

6.2 图形化

或者可以直接输入web,通过svg图的方式查看程序中详细的CPU占用情况。
想要查看图形化的界面首先需要安装graphviz图形化工具。

Mac:

brew install graphviz

Windows:
下载graphviz
graphviz安装目录下的bin文件夹添加到Path环境变量中。
在终端输入dot -version查看是否安装成功。


关于图形的说明:
每个框代表一个函数,理论上框的越大表示占用的CPU资源越多。
方框之间的线条代表函数之间的调用关系。
线条上的数字表示函数调用的次数。
方框中的第一行数字表示当前函数占用CPU的百分比,第二行数字表示当前函数累计占用CPU的百分比。

七、go-torch和火焰图

火焰图(Flame Graph)是 Bredan Gregg 创建的一种性能分析图表,因为它的样子近似

Go pprof性能调优的更多相关文章

  1. golang 性能调优分析工具 pprof (上)

    一.golang 程序性能调优 在 golang 程序中,有哪些内容需要调试优化? 一般常规内容: cpu:程序对cpu的使用情况 - 使用时长,占比等 内存:程序对cpu的使用情况 - 使用时长,占 ...

  2. golang 性能调优分析工具 pprof(下)

    golang 性能调优分析工具 pprof(上)篇, 这是下篇. 四.net/http/pprof 4.1 代码例子 1 go version go1.13.9 把上面的程序例子稍微改动下,命名为 d ...

  3. Golang性能调优入门

    如何利用golang自带的profile工具进行应用程序的性能调优,前一段时间我做的日志分析系统在线上遇到了一个问题,就是分任务的系统down机了,日志处理延迟了10几个小时,这个时候任务分发系统重启 ...

  4. Go性能调优

    文章引用自   Go性能调优 在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况. Go语言是一个对性能特别看重的语言,因此语言中自带了 pr ...

  5. GO学习-(21) Go语言基础之Go性能调优

    Go性能调优 在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况. Go语言是一个对性能特别看重的语言,因此语言中自带了 profiling ...

  6. web前端性能调优

    最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...

  7. [网站性能2]Asp.net平台下网站性能调优的实战方案

    文章来源:http://www.cnblogs.com/dingjie08/archive/2009/11/10/1599929.html 前言    最近帮朋友运营的平台进行了性能调优,效果还不错, ...

  8. Asp.net平台下网站性能调优的实战方案(转)

    转载地址:http://www.cnblogs.com/chenkai/archive/2009/11/07/1597795.html 前言 最近帮朋友运营的平台进行了性能调优,效果还不错,所以写出来 ...

  9. 第0/24周 SQL Server 性能调优培训引言

    大家好,这是我在博客园写的第一篇博文,之所以要开这个博客,是我对MS SQL技术学习的一个兴趣记录. 作为计算机专业毕业的人,自己对技术的掌握总是觉得很肤浅,博而不专,到现在我才发现自己的兴趣所在,于 ...

随机推荐

  1. idea 新建不了servlet文件 方法(1)

    在pem.xml中添加较新版本的servletapi包 <dependency> <groupId>javax.servlet</groupId> <arti ...

  2. 第十章 Centos7-系统进程管理 随堂笔记

    第十章 Centos7-系统进程管理 本节所讲内容: 10.1 进程概述和ps查看进程工具 10.2 uptime查看系统负载-top动态管理进程 10.3 前后台进程切换- nice进程优先级-实战 ...

  3. 高性能MySQL之基础架构

    一.背景 为什么我们需要先学习MYSQL的基础架构先呢? 原因很简单,当我们需要了解一件事物的时候,我们只有站在宏观的层面,才能层层剥丝抽茧的去理解问题.举个例子,我们要看一个框架的源码,一开始就想进 ...

  4. Python中input()的使用方法

    input()以字符串的方式获取用户输入: >>> x = input() 4.5 >>> type(x) <class 'str'> >> ...

  5. java多线程基础(一)--sleep和wait的区别

    sleep和wait的区别有: 1.这两个方法来自不同的类分别是Thread和Object: 2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得线程可以使用同步控制块或者方法: 3.w ...

  6. 算法之《图》Java实现

    数据结构之图 定义(百度百科) 图的术语表 无向图 深度优先搜索 广度优先遍历 有向图 路径问题 调度问题 强连通性 最小生成树(无向图) 最小生成树的贪心算法 加权无向图的数据结构 Kruskal算 ...

  7. go 学习笔记之值得特别关注的基础语法有哪些

    在上篇文章中,我们动手亲自编写了第一个 Go 语言版本的 Hello World,并且认识了 Go 语言中有意思的变量和不安分的常量. 相信通过上篇文章的斐波那契数列,你已经初步掌握了 Go 语言的变 ...

  8. 如何彻底禁用 werfalut.exe

    在程序中调用 控制台程序 的时候,一旦出现控制台出现 crash 往往会弹出 werfault 窗口, 这样往往会锁死线程,导致程序无法继续运行. 那如何禁止 werfault 窗口的弹出呢? 在 s ...

  9. 06 css选择器

    选择器的作用:选中标签 1.基本选择器  标签选择器 id选择器 class选择器 *通配符选择器 权重:行内样式 1000 > id选择器 100 > 类选择器10 > 标签选择器 ...

  10. 【模板】树链剖分(Luogu P3384)

    题目描述 众所周知 树链剖分是个好东西QWQ 也是一个代码量破百的算法 基本定义 树路径信息维护算法. ž将一棵树划分成若干条链,用数据结构去维护每条链,复杂度为O(logN). 其实本质是一些数据结 ...