• go程序性能测量和分析


    • 性能测量

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

     1 //斐波那契数
     2 package fib
     3 
     4 import "math"
     5 
     6 //递归方式
     7 func Fib(n int) int {
     8     if n < 2 {
     9         return n
    10     }
    11     return Fib(n-1) + Fib(n-2)
    12 }
    13 
    14 //迭代方式
    15 func Fib2(n int) int {
    16     if n < 2 {
    17         return n
    18     }
    19     a := 1
    20     b := 1
    21     c := 1
    22     for i := 2; i < n; i++ {
    23         c =  a + b
    24         a = b
    25         b = c
    26     }
    27     return c;
    28 }
    29 
    30 //公式求解
    31 func Fib3(n int) int {
    32     gh5 := math.Sqrt(5)
    33     pow := math.Pow
    34     f := (float64)(n)
    35     return (int)(math.Ceil((pow(1+gh5, f) - pow(1-gh5,f)) / (pow(2.0, f) * gh5)))
    36 }
    上面的代码提供了3种求斐波那契数的方法,毫无疑问第一种方式是最不可取的。但是第二种和第三种方式到底哪一个性能更好呢?好多人可能会说是第三种。口说无凭,写个测试用例看看:
     1 package fib_test
     2 
     3 import (
     4     "testing"
     5     "goperformance/fib"
     6 )
     7 
     8 func Test_Fib(t *testing.T) {
     9     println(fib.Fib(40))
    10 }
    11 
    12 func Test_Fib2(t *testing.T)  {
    13     println(fib.Fib2(40))
    14 }
    15 
    16 func Test_Fib3(t *testing.T)  {
    17     println(fib.Fib3(40))
    18 }
    19 
    20 func Benchmark_Fib(b *testing.B) {
    21     for i := 0; i < b.N; i++ {
    22         fib.Fib(i%40)
    23     }
    24 }
    25 
    26 func Benchmark_Fib2(b *testing.B) {
    27     for i := 0; i < b.N; i++ {
    28         fib.Fib2(i%40)
    29     }
    30 }
    31 
    32 func Benchmark_Fib3(b *testing.B) {
    33     for i := 0; i < b.N; i++ {
    34         fib.Fib3(i%40)
    35     }
    36 }

    执行 #go test -bench=. -v

     1 === RUN   Test_Fib
     2 102334155
     3 --- PASS: Test_Fib (0.63s)
     4 === RUN   Test_Fib2
     5 102334155
     6 --- PASS: Test_Fib2 (0.00s)
     7 === RUN   Test_Fib3
     8 102334155
     9 --- PASS: Test_Fib3 (0.00s)
    10 PASS
    11 Benchmark_Fib-4              100          20280130 ns/op
    12 Benchmark_Fib2-4        100000000               13.4 ns/op
    13 Benchmark_Fib3-4        10000000               123 ns/op
    14 ok      goperformance/fib       6.086s

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

    • 性能分析

    1,使用标准库runtime/pprof

     1 package main
     2 
     3 import (
     4     "goperformance/fib"
     5     "flag"
     6     "log"
     7     "os"
     8     "runtime/pprof"
     9 )
    10 
    11 var cpuprofile = flag.String("cpuprofile", "cpu.prof", "write cpu profile to file")
    12 
    13 func main() {
    14     flag.Parse()
    15     f, err := os.Create(*cpuprofile)
    16     if err != nil {
    17         log.Fatal(err)
    18     }
    19     pprof.StartCPUProfile(f)
    20     defer pprof.StopCPUProfile()
    21     println(fib.Fib(40))
    22     println(fib.Fib2(40))
    23     println(fib.Fib3(40))
    24 }

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

    1 srcgoperformance>go build
    2 srcgoperformance>goperformance.exe
    3 102334155
    4 102334155
    5 102334155
    6 srcgoperformance>go tool pprof goperformance.exe cpu.prof
    7 Entering interactive mode (type "help" for commands)
    8 (pprof) web
    9 (pprof)

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

    2,使用github.com/pkg/profile

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

     1 package main
     2 
     3 import (
     4     "goperformance/fib"
     5     "github.com/pkg/profile"
     6 )
     7 
     8 func main() {
     9     defer profile.Start().Stop() //可以通过不同的参数确定是cpu性能分析还是内存使用分析
    10     println(fib.Fib(40))
    11     println(fib.Fib2(40))
    12     println(fib.Fib3(40))
    13 }

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

     

  • 相关阅读:
    linux快速安装lamp环境
    linux配置网卡
    给linux添加yum源。
    windows 环境下wamp环境的搭建。
    jQuery知识点总结(第六天)
    LazyLoad学习(一)之无阻塞动态尽可能并行加载脚本文件以及确保执行顺序
    Jquery复习(十)之$的用法
    JavaScript 时间与日期处理
    如何将一个HTML页面嵌套在另一个页面中?
    iframe学习(七)之父窗口的样式会影响子窗口吗?
  • 原文地址:https://www.cnblogs.com/borey/p/5622676.html
Copyright © 2020-2023  润新知