基准 Go 代码和 goroutines

Posted

技术标签:

【中文标题】基准 Go 代码和 goroutines【英文标题】:Benchmark Go code and goroutines 【发布时间】:2016-02-05 19:20:57 【问题描述】:

我想对一个函数进行基准测试:test(),使用不同数量的线程处理它。

没有 goroutine:

var t1 = time.Now()
test()
var elapsed1 = time.Since(t1)

1 ns / 操作

使用 goroutine:

runtime.GOMAXPROCS(1)
var t1 = time.Now()
go test()
var elapsed1 = time.Since(t1)

1.10^-6 ns / 操作

我的测试功能:

func test() 
    for i := 0; i < 1000000000; i++ 
        float_result = f1 + f2
        float_result = f1 - f2
        float_result = f1 * f2
        float_result = f1 / f2
        float_result = f1 + f2
        float_result = f1 - f2
        float_result = f1 * f2
        float_result = f1 / f2
        float_result = f1 + f2
        float_result = f1 - f2
        float_result = f1 * f2
        float_result = f1 / f2
        float_result = f1 + f2
        float_result = f1 - f2
        float_result = f1 * f2
        float_result = f1 / f2
        float_result = f1 + f2
        float_result = f1 - f2
        float_result = f1 * f2
        float_result = f1 / f2
    

在这种情况下,当我使用 goroutine 时,test() 函数的基准测试是否良好? 如何达到 0.001ns/操作?它看起来太快了。 (2.5GHz 英特尔酷睿 i7) 使用带有runtime.GOMAXPROCS(n) 的goroutines 是否等同于使用n 个线程?

【问题讨论】:

任何语言的任何体面的编译器都会丢弃循环中的几乎所有代码,因为您的 float_result 值从未使用过。您需要将其写入输出或文件。 即使你在最后使用了 float_result,也只有最后一行会运行,因为所有其他行都被覆盖了。 我想做很多操作,不多次使用同一个变量怎么办?如果我做var = f1 + f2 + f3 + f4,编译后直接写f1 + f2 + f3 + f4的值,不行吗? 【参考方案1】:

您测量的不是test() 运行的时间,而是使用go test() 调用/创建新goroutine 所需的时间。

您需要等待 goroutine 完成,例如使用 sync.Waitgroup。

// somewhere in your main package
var wg sync.WaitGroup

func test() 
   // first lines in test() should be
   wg.Add(1)
   defer wg.Done()
   ...



// benchmark
runtime.GOMAXPROCS(1)
var t1 = time.Now()
go test()
wg.Wait()
var elapsed1 = time.Since(t1)

【讨论】:

【参考方案2】:

您正在尝试对小到以测量误差为主的事物进行基准测试。您的基准测试迭代应该进行调整,直到基准功能持续足够长的时间以可靠地计时。您的基准测试应该运行大约一秒钟才有意义。

【讨论】:

即使我在 test() 函数中有 100 亿个循环,我也有相同的结果。而且,有了runtime.GOMAXPROCS(1),应该不会比没有goroutine那么大吧? @Nico401:向我们展示您的测试功能:How to create a Minimal, Complete, and Verifiable example.。 我做到了,我相信你会认出它:) @Nico401:“与常规调用不同,程序执行不会等待调用的函数完成。” Go statements。所以你把 goroutine 交给了调度器,得到了时间,然后结束了程序。没多久!

以上是关于基准 Go 代码和 goroutines的主要内容,如果未能解决你的问题,请参考以下文章

Go中的单元测试和基准测试

Go语言之基准测试

go语言单元测试和基准测试

#yyds干货盘点#Go 语言入门很简单:基准测试

Go语言基准测试(benchmark)三部曲之一:基础篇

golang基准测试详解