go性能优化

Go性能优化

  • CPU profile:报告程序CPU使用情况,按照一定频率去采集应用程序CPU和寄存器上面的数据
  • Memory Profile (Heap Profile):报告内存使用情况
  • Block Profiling:报告goroutines不在运行状况情况下,可以用来分析和查找死锁等性能瓶颈
  • Goroutine Profiling:报告goroutine的使用情况,有哪些goroutine它们调用关系是怎样的
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", v)
		default:
			time.Sleep(time.Second) // 耗费CPU的时候注释这行

		}
	}
}

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("creat cpu pprof failed, err : %v", err)
			return
		}
		_ = pprof.StartCPUProfile(file)
		defer pprof.StopCPUProfile()

	}
	for i:=0; i < 8; i++ {
		go logicCode()
	}
	time.Sleep(6 * time.Second)

	if isMemPprof {
		file, err := os.Create("./mem.pprof")
		if err != nil {
			fmt.Printf("create mem pprof failed, err : %v", err)
			return
		}
		_ = pprof.WriteHeapProfile(file)
		file.Close()
	}

}

编译:

andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ go build pprofile_demo.go 
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ ./pprofile_demo -cpu=true
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ go tool pprof cpu.pprof 
File: pprofile_demo
Type: cpu
Time: Dec 21, 2020 at 11:08pm (CST)
Duration: 20.17s, Total samples = 58.35s (289.35%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top 5
Showing nodes accounting for 58.25s, 99.83% of 58.35s total
Dropped 14 nodes (cum <= 0.29s)
      flat  flat%   sum%        cum   cum%
    27.16s 46.55% 46.55%     46.38s 79.49%  runtime.selectnbrecv
    19.22s 32.94% 79.49%     19.22s 32.94%  runtime.chanrecv
    11.87s 20.34% 99.83%     58.25s 99.83%  main.logicCode
(pprof) quit

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

使用命令查看,具体哪个函数浪费了比较多的时间

andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ go build pprofile_demo.go 
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ ./pprofile_demo -cpu=true
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ go tool pprof cpu.pprof 
File: pprofile_demo
Type: cpu
Time: Dec 21, 2020 at 11:23pm (CST)
Duration: 6.15s, Total samples = 17.10s (277.95%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top 3
Showing nodes accounting for 17.10s, 100% of 17.10s total
      flat  flat%   sum%        cum   cum%
     7.79s 45.56% 45.56%     13.18s 77.08%  runtime.selectnbrecv
     5.39s 31.52% 77.08%      5.39s 31.52%  runtime.chanrecv
     3.92s 22.92%   100%     17.10s   100%  main.logicCode
(pprof) list logicCode
Total: 17.10s
ROUTINE ======================== main.logicCode in /home/andrew/go/src/basic/pprof_demo/pprofile_demo.go
     3.92s     17.10s (flat, cum)   100% of Total
         .          .     11:// 一段有问题的代码
         .          .     12:func logicCode() {
         .          .     13:   var c chan int
         .          .     14:   for {
         .          .     15:           select {
     3.92s     17.10s     16:           case v := <- c:
         .          .     17:                   fmt.Printf("recv from chan, value:%v", v)
         .          .     18:           default:
         .          .     19:                   //time.Sleep(time.Second)
         .          .     20:
         .          .     21:           }
(pprof) web  # 如果装的有graphviz工具,这里会在浏览器打开一个svg图片如下:

go性能优化

使用go绘制火焰图

讲到这里就不得不说下,使用go绘制火焰图分析代码性能:

  1. 第一步安装pprof
go get github.com/google/pprof

要是遇到提示没有权限,参考: go get提示没有 权限解决

直接使用pprof分析:

pprof -http=:8080 cpu.prof

执行之后会在浏览器中打开,并显示对程序的分析图

  1. 安装FlameGraph
git clone https://github.com/brendangregg/FlameGraph.git
export PATH=$PATH:home/FlameGraph #换成自己的路径
  1. 安装graphviz
sudo apt-get install graphviz
  1. 安装go-torch
go get github.com/uber/go-torch

go-torch 工具的使用非常简单,没有任何参数的话,它会尝试从 http://localhost:8080/debug/pprof/profile 获取 profiling 数据。它有三个常用的参数可以调整:

-u --url:要访问的 URL,这里只是主机和端口部分
-s --suffix:pprof profile 的路径,默认为 /debug/pprof/profile
-t --seconds:要执行 profiling 的时间长度,默认为 30s

火焰图的调用顺序从下到上,每个方块代表一个函数,它上面一层表示这个函数会调用哪些函数,方块的大小代表了占用 CPU 使用的长短,火焰图的配色并没有特殊的意义。

上一篇:2021-03-12:go中,如何确定有没有内存泄露,系统里怎么去监控整体的运行情况,日志是怎么处理


下一篇:【C/C++】C和C++11之enum枚举的使用细节