我正在尝试找出哪种模式在Go中迭代一系列值的速度最快。每一个都有明显的优点和缺点,但速度将是我的用例的一个重要因素
不出所料,频道是最慢的。
然而,我很惊讶,所以看到回调和生成器模式之间有巨大的差异,我试图理解发生了什么。在我看来,性能应该大致相同,但事实并非如此。
两者调用匿名函数的次数相同,但我想知道是否有什么与上下文切换有关。
下层是怎么回事?
我得到了这些结果:
BenchmarkIteratorMethods/generator-8 31970 36196 ns/op
BenchmarkIteratorMethods/callback-8 1000000 1193 ns/op
BenchmarkIteratorMethods/channel-8 7999 148906 ns/op我的基准代码:
package test
import (
"testing"
)
const iteratorTestIterations = 1000
func iteratorGeneratorFunctionForTests() func() (int, bool) {
i := 0
return func() (int, bool) {
for i < iteratorTestIterations {
defer (func() {
i++
})()
return i, false
}
return 0, true
}
}
func iteratorCallbackForTests(callback func(value int) bool) {
for i := 0; i < iteratorTestIterations; i++ {
shouldContinue := callback(i)
if !shouldContinue {
break
}
}
}
func iteratorChannelForTests() chan int {
channel := make(chan int)
go (func() {
for i := 0; i < iteratorTestIterations; i++ {
channel <- i
}
close(channel)
})()
return channel
}
func BenchmarkIteratorMethods(b *testing.B) {
b.Run("generator", func(b *testing.B) {
for i := 0; i < b.N; i++ {
iterator := iteratorGeneratorFunctionForTests()
for {
value, end := iterator()
if end {
break
}
_ = value
}
}
})
b.Run("callback", func(b *testing.B) {
for i := 0; i < b.N; i++ {
iteratorCallbackForTests(func(value int) bool {
_ = value
return true
})
}
})
b.Run("channel", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for value := range iteratorChannelForTests() {
_ = value
}
}
})
}发布于 2021-03-26 21:29:38
我找到原因了。它实际上与我的代码相关。函数的延迟太慢。
我将第一个函数替换为:
func iteratorGeneratorFunctionForTests() func() (int, bool) {
i := 0
return func() (int, bool) {
for i < iteratorTestIterations {
value := i
i++
return value, false
}
return 0, true
}
}现在我得到了更符合逻辑的结果:
BenchmarkIteratorMethods/generator-8 773698 1442 ns/op
BenchmarkIteratorMethods/callback-8 966046 1168 ns/op
BenchmarkIteratorMethods/channel-8 7710 145243 ns/ophttps://stackoverflow.com/questions/66817813
复制相似问题