我在优步风格指南上读到,最多应该使用1的通道长度。
虽然我很清楚,使用100或1000个通道大小是非常糟糕的做法,但是我想知道为什么10的通道大小不能被认为是一个有效的选择。为了得出正确的结论,,我遗漏了一些部分。
下面,您可以遵循我的论点(和反参数)支持的一些基准测试。
我知道,如果你的两个去例程,负责从这个频道写或读,会在连续的写作或阅读之间被其他的IO动作打断,那么从一个更高的通道缓冲器中得不到任何收益,我同意1是最好的选择。
但是,让我们说,除了对通道的写/读所导致的隐式锁定和解锁之外,没有其他重要的常规切换需要。然后我要总结如下:
考虑使用大小为1和10的通道缓冲区在通道上处理100个值时,上下文开关的数量(GR =go-例程)
我做了一些基准测试,以证明这实际上更快:
package main
import (
"testing"
)
type a struct {
b [100]int64
}
func BenchmarkBuffer1(b *testing.B) {
count := 0
c := make(chan a, 1)
go func() {
for i := 0; i < b.N; i++ {
c <- a{}
}
close(c)
}()
for v := range c {
for i := range v.b {
count += i
}
}
}
func BenchmarkBuffer10(b *testing.B) {
count := 0
c := make(chan a, 10)
go func() {
for i := 0; i < b.N; i++ {
c <- a{}
}
close(c)
}()
for v := range c {
for i := range v.b {
count += i
}
}
}结果在比较简单读写+非阻塞处理时:
BenchmarkBuffer1-12 5072902 266 ns/op
BenchmarkBuffer10-12 6029602 179 ns/op
PASS
BenchmarkBuffer1-12 5228782 256 ns/op
BenchmarkBuffer10-12 5392410 216 ns/op
PASS
BenchmarkBuffer1-12 4806208 287 ns/op
BenchmarkBuffer10-12 4637842 233 ns/op
PASS然而,如果我每10次读取一次睡眠,它不会产生任何更好的结果。
import (
"testing"
"time"
)
func BenchmarkBuffer1WithSleep(b *testing.B) {
count := 0
c := make(chan int, 1)
go func() {
for i := 0; i < b.N; i++ {
c <- i
}
close(c)
}()
for a := range c {
count++
if count%10 == 0 {
time.Sleep(time.Duration(a) * time.Nanosecond)
}
}
}
func BenchmarkBuffer10WithSleep(b *testing.B) {
count := 0
c := make(chan int, 10)
go func() {
for i := 0; i < b.N; i++ {
c <- i
}
close(c)
}()
for a := range c {
count++
if count%10 == 0 {
time.Sleep(time.Duration(a) * time.Nanosecond)
}
}
}结果每10次增加一次睡眠时:
BenchmarkBuffer1WithSleep-12 856886 53219 ns/op
BenchmarkBuffer10WithSleep-12 929113 56939 ns/opFYI:我还用一个CPU做了一次测试,得到了以下结果:
BenchmarkBuffer1 5831193 207 ns/op
BenchmarkBuffer10 6226983 180 ns/op
BenchmarkBuffer1WithSleep 556635 35510 ns/op
BenchmarkBuffer10WithSleep 984472 61434 ns/op发布于 2021-02-03 07:57:42
当然,上限500的信道没有任何问题,例如,如果使用此信道作为信号量。
您阅读的样式指南建议不要使用缓冲通道,比方说第64页,“因为这看起来是个不错的数字”。但是这个推荐并不是因为性能!(顺便说一句:你的微基准是无用的微基准,它们不衡量任何相关的东西。)
无缓冲信道是一种同步原语,我们非常有用。
缓冲通道可能会在发送方和接收方之间缓冲,而这种缓冲对于观察、调优和调试代码可能会有问题(因为创建和消耗是进一步解耦的)。这就是为什么样式指南推荐未缓冲的通道(或者最多为1,因为这有时是正确性所必需的!)。
它也不禁止更大的缓冲区上限:
除0或1大小以外的任何其他大小都必须接受高级别的审查。考虑大小是如何确定的,在加载和阻塞写入器下,是什么阻止了通道的填充,以及当发生这种情况时会发生什么。空的。我的
如果您可以解释为什么27 (而不是22或31)以及这将如何影响程序行为(不仅是性能!),您可以使用27上限。如果缓冲区已被填充。
大多数人高估了表现。正确性、操作稳定性和可维护性是第一位的。这就是这个风格指南的意义所在。
https://stackoverflow.com/questions/66022963
复制相似问题