go程序性能测量和分析
博客专区 > borey 的博客 > 博客详情
go程序性能测量和分析
borey 发表于2年前
go程序性能测量和分析
  • 发表于 2年前
  • 阅读 124
  • 收藏 5
  • 点赞 2
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

  • 性能测量

    在很多情况之下,通过分析代码是很难确定某个模块性能好坏的。请看下面的例子,你觉得哪一个函数性能最优?

//斐波那契数
package fib

import "math"

//递归方式
func Fib(n int) int {
    if n < 2 {
        return n
    }
    return Fib(n-1) + Fib(n-2)
}

//迭代方式
func Fib2(n int) int {
    if n < 2 {
        return n
    }
    a := 1
    b := 1
    c := 1
    for i := 2; i < n; i++ {
        c =  a + b
        a = b
        b = c
    }
    return c;
}

//公式求解
func Fib3(n int) int {
    gh5 := math.Sqrt(5)
    pow := math.Pow
    f := (float64)(n)
    return (int)(math.Ceil((pow(1+gh5, f) - pow(1-gh5,f)) / (pow(2.0, f) * gh5)))
}

上面的代码提供了3种求斐波那契数的方法,毫无疑问第一种方式是最不可取的。但是第二种和第三种方式到底哪一个性能更好呢?好多人可能会说是第三种。口说无凭,写个测试用例看看:

package fib_test

import (
    "testing"
    "goperformance/fib"
)

func Test_Fib(t *testing.T) {
    println(fib.Fib(40))
}

func Test_Fib2(t *testing.T)  {
    println(fib.Fib2(40))
}

func Test_Fib3(t *testing.T)  {
    println(fib.Fib3(40))
}

func Benchmark_Fib(b *testing.B) {
    for i := 0; i < b.N; i++ {
        fib.Fib(i%40)
    }
}

func Benchmark_Fib2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        fib.Fib2(i%40)
    }
}

func Benchmark_Fib3(b *testing.B) {
    for i := 0; i < b.N; i++ {
        fib.Fib3(i%40)
    }
}

执行 #go test -bench=. -v

=== RUN   Test_Fib
102334155
--- PASS: Test_Fib (0.63s)
=== RUN   Test_Fib2
102334155
--- PASS: Test_Fib2 (0.00s)
=== RUN   Test_Fib3
102334155
--- PASS: Test_Fib3 (0.00s)
PASS
Benchmark_Fib-4              100          20280130 ns/op
Benchmark_Fib2-4        100000000               13.4 ns/op
Benchmark_Fib3-4        10000000               123 ns/op
ok      goperformance/fib       6.086s

很明显第二种方式比第三种方式要快100多倍。性能测量为我们编写高性能的go程序提供了可靠的依据。

  • 性能分析

1,使用标准库runtime/pprof

package main

import (
	"goperformance/fib"
	"flag"
	"log"
	"os"
	"runtime/pprof"
)

var cpuprofile = flag.String("cpuprofile", "cpu.prof", "write cpu profile to file")

func main() {
	flag.Parse()
	f, err := os.Create(*cpuprofile)
	if err != nil {
		log.Fatal(err)
	}
	pprof.StartCPUProfile(f)
	defer pprof.StopCPUProfile()
	println(fib.Fib(40))
	println(fib.Fib2(40))
	println(fib.Fib3(40))
}

编译并执行程序获得性能分析文件

\src\goperformance>go build
\src\goperformance>goperformance.exe
102334155
102334155
102334155
\src\goperformance>go tool pprof goperformance.exe cpu.prof
Entering interactive mode (type "help" for commands)
(pprof) web
(pprof)

在web中展示出来的分析结果如下:

2,使用github.com/pkg/profile

profile包实际上是对runtime/pprof的封装,使用起来更加友好

package main

import (
	"goperformance/fib"
	"github.com/pkg/profile"
)

func main() {
	defer profile.Start().Stop() //可以通过不同的参数确定是cpu性能分析还是内存使用分析
	println(fib.Fib(40))
	println(fib.Fib2(40))
	println(fib.Fib3(40))
}

运行程序后在缓存自动生成一个临时文件,这个文件就是上一种方式中的cpu.prof文件。接下来的操作就和第一种方式一样。


  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 26
博文 54
码字总数 31182
×
borey
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: