英文:
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 (
"testing"
"time"
)
func Hi() {
time.Sleep(5 * time.Nanosecond)
}
func BenchmarkHi(b *testing.B) {
for i := 0; i < 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:
答案2
得分: 4
《如何编写准确的Go基准测试》(Teiva Harsanyi,2022年8月)和《基准测试维基页面》都提到了Linux上的perflock
:
我们应该确保执行基准测试的机器处于空闲状态。然而,外部进程可能在后台运行,这可能会影响基准测试结果。
出于这个原因,像
perflock
这样的工具可以限制基准测试消耗的CPU数量。例如,我们可以使用总可用CPU的70%来运行基准测试,将30%留给操作系统和其他进程,从而减少机器活动因素对结果的影响。
另请参阅《问题44343:runtime
:time.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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论