非常短的time.Sleep为什么在基准测试中比请求的时间(约300纳秒)要长?

huangapple go评论76阅读模式
英文:

Why does a very short time.Sleep take longer than the requested (about 300 ns) in benchmarks?

问题

我正在玩Go语言的基准测试,并且有一个简单的函数,只是休眠5纳秒,但是当我运行基准测试时,显示的是298.1 ns/op。我很好奇为什么会这样。难道不应该是5 ns/op吗?

Go版本:

go version go1.19 linux/amd64

代码:

package andrei

import (
	"testing"
	"time"
)

func Hi() {
	time.Sleep(5 * time.Nanosecond)
}

func BenchmarkHi(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Hi()
	}
}

结果:

$ go test -run none -bench . -benchmem ./andrei

goos: linux
goarch: amd64
pkg: andrei/andrei
cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
BenchmarkHi-8 3861392 298.1 ns/op 0 B/op 0 allocs/op
PASS
ok andrei/andrei 1.470s
英文:

I'm playing around with benchmarks in Go and I have a simple function that just sleeps for 5 Nanoseconds, however when I run a benchmark test it shows 298.1 ns/op. I'm curious why is that. Shouldn't it be 5 ns/op?

Go version:

go version go1.19 linux/amd64

The code:

package andrei

import (
	&quot;testing&quot;
	&quot;time&quot;
)

func Hi() {
	time.Sleep(5 * time.Nanosecond)
}

func BenchmarkHi(b *testing.B) {
	for i := 0; i &lt; b.N; i++ {
		Hi()
	}
}

The results:

$ go test -run none -bench  . -benchmem ./andrei

goos: linux
goarch: amd64
pkg: andrei/andrei
cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
BenchmarkHi-8            3861392               298.1 ns/op             0 B/op          0 allocs/op
PASS
ok      andrei/andrei   1.470s

答案1

得分: 5

time.Sleep只保证至少睡眠与参数相同的时间。它实际上睡眠的时间取决于你的操作系统和其他因素。

在Windows上,它至少睡眠1.9毫秒。在我的MacBook上,我得到了408纳秒/操作,而你看到的是298.1纳秒/操作。

你可以在Go的GitHub存储库中的这个问题票中找到更多关于这个问题的详细信息:

https://github.com/golang/go/issues/29485

英文:

time.Sleep only guarantees that it will sleep at least as long as the argument. How long it actually sleeps depends on your operating system and other factors.

On Windows, it sleeps at least 1.9ms. On my MacBook, I get 408 ns/op, and you are seeing 298.1 ns/op.

You can find out more details about this problem in this ticket in the Go github repository:

https://github.com/golang/go/issues/29485

答案2

得分: 4

《如何编写准确的Go基准测试》(Teiva Harsanyi,2022年8月)和《基准测试维基页面》都提到了Linux上的perflock

我们应该确保执行基准测试的机器处于空闲状态。然而,外部进程可能在后台运行,这可能会影响基准测试结果。

出于这个原因,像perflock这样的工具可以限制基准测试消耗的CPU数量。

例如,我们可以使用总可用CPU的70%来运行基准测试,将30%留给操作系统和其他进程,从而减少机器活动因素对结果的影响。

另请参阅《问题44343:runtimetime.Sleep所需时间超过预期》。

对于Linux,我们应该使用epoll_pwait2,例如https://go.dev/cl/363417。
这个系统调用是较新的,但这将改善未来的情况,并为受影响的用户提供一个解决方法(升级内核)。

英文:

The article "How to Write Accurate Benchmarks in Go" (Teiva Harsanyi, Aug. 2022) and the Benchmarks wiki page both mention perflock (on Linux):

> We should make sure the machine executing the benchmark is idle. However, external processes may run in the background, which may affect benchmark results.
>
> For that reason, tools such as perflock can limit how much CPU a benchmark can consume.
>
> For example, we can run a benchmark with 70% of the total available CPU, giving 30% to the OS and other processes and reducing the impact of the machine activity factor on the results.

See also "issues 44343: runtime: time.Sleep takes more time than expected".

> For Linux, we should use epoll_pwait2, like https://go.dev/cl/363417.
This system call is on the newer side, but this will improve things going forward and provide a workaround (upgrade the kernel) for particularly affected users.

huangapple
  • 本文由 发表于 2022年9月2日 13:45:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/73578241.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定