测量Go程序中的执行时间

开发Go应用程序或对其进行基准测试以找到改进方法的常见操作是对函数执行时间进行基准测试。我介绍了Go中的CPU和内存配置文件已经存在,但这是不同的,更适合临时功能执行时间的测量。

确定两个表达式之间的时间间隔:使用time.Since

time.Since是由time标准库程序包需要一个Time值,计算与当前时间的差,然后返回Duration值,它是一个int64类型,带有String()附带的方法,它为计算的时间提供了人性化的符号。

import (
    "fmt"
    "time"
)

func main() { start := time.Now()

<span style="color:#75715e">//... do something

fmt.Println(time.Since(start)) }

在内部,time.Since是的简写time.Now().Sub(t)

使用defer测量功能内部的时间

您可以通过使用defer

package main

import ( “log” “time” )

func runningtime(s string) (string, time.Time) { log.Println("Start: ", s) return s, time.Now() }

func track(s string, startTime time.Time) { endTime := time.Now() log.Println("End: ", s, “took”, endTime.Sub(startTime)) }

func execute() { defer track(runningtime(“execute”)) time.Sleep(3 * time.Second) }

func main() { execute() }

通过多次运行来对功能性能进行基准测试:使用testing包裹

这是我写的一个简单的库,它计算字符串中的符文数。

runecount.go

package runecount

import “unicode/utf8”

func RuneCount(s string) int { return len([]rune(s)) }

func RuneCount2(s string) int { return utf8.RuneCountInString(s) }

计算字符串中的符文的两种方法中哪一种更快?我们通过编写基准来找出答案。基准存在于*_test.go文件,例如常规测试,并且可以保留以以下各项开头的测试方法Test*,但它们以Benchmark*反而:

runecount_test.go

package runecount

import “testing”

func BenchmarkRuneCount(b testing.B) { s := “Gophers are amazing 😁” for i := 0; i < b.N; i++ { RuneCount(s) } } func BenchmarkRuneCount2(b testing.B) { s := “Gophers are amazing 😁” for i := 0; i < b.N; i++ { RuneCount2(s) } }

我通过在文件所在的同一文件夹中执行来运行此命令:

go test -bench=.

这将导致所有基准测试运行。我只有一个文件,但是如果有很多文件,则可以指定要运行的文件。

每个基准运行循环,并传递bN变量,该变量由基准运行程序自动确定,直到平均值稳定到足以确定结果为止。

这是我在Mac上获得的输出:

# flavio @ Flavios-MacBook-Pro in ~/go/src/github.com/flaviocopes/snippets/benchmark on git:master x [18:32:26]
$ go test -bench=.
BenchmarkRuneCount-2            20000000               115 ns/op
BenchmarkRuneCount2-2           30000000                44.1 ns/op
PASS
ok      github.com/flaviocopes/snippets/benchmark       3.812s

2000000030000000是运行的操作数。

该命令返回基准测试结果:运行了2000万次RuneCount(),平均耗时163纳秒,然后运行了3000万次RuneCount2(),每次迭代平均需要74.2纳秒。

所以Benchmark1,它运行RuneCount(),比慢2倍RuneCount2(),即使用内置utf8.RuneCountInString功能。毫不奇怪,因为utf8.RuneCountInString针对此特定任务进行了高度优化。


而不是使用go test,您也可以致电testing.Benchmark从命令:

package main

import ( “fmt” “testing” “runecount” )

func BenchmarkRuneCount(b testing.B) { s := “Gophers are amazing 😁” for i := 0; i < b.N; i++ { RuneCount(s) } } func BenchmarkRuneCount2(b testing.B) { s := “Gophers are amazing 😁” for i := 0; i < b.N; i++ { RuneCount2(s) } }

func main() { fmt.Println(testing.Benchmark(BenchmarkRuneCount)) fmt.Println(testing.Benchmark(BenchmarkRuneCount2)) }

在哪里阅读更多


更多教程: