【发布时间】:2018-07-25 07:22:28
【问题描述】:
我遇到了一个奇怪的行为。我在玩缓冲通道,当使用大缓冲区时,整个程序执行会阻塞。在下面的代码sn-p中:
package main
import (
"fmt"
)
func main() {
choke := make(chan string, 150000)
go func() {
for i := 0; i < 10000000; i++ {
choke <- string(i)
fmt.Println("i=", i)
}
}()
for {
//fmt.Println(len(choke))
if len(choke) >= 150000 {
fmt.Println("Full")
}
}
}
我的程序在 ~96000 次迭代时阻塞并且永远不会达到“完整”打印,除非我在评估它之前打印出 len(choke)。这可能是由于fmt.Println 提供的延迟,因为这个问题也可以通过添加一个小的time.Sleep 来“修复”。
有人可以解释这种行为的原因吗?
【问题讨论】:
-
你有一个紧密的循环,它将尽可能多地使用 CPU。获取通道的长度需要锁定通道,因此它会尽可能快地不断锁定和解锁它。您还在检查缓冲区大小是否为
>=,这意味着您认为它的长度有可能超过其最大大小,这在定义上是不可能的。 -
@Adrian 但问题是:为什么打印通道长度可以解决问题?
-
很难说,你没有显示那个代码。
-
@Adrian 在
if len(choke) >= 150000的正上方有一个fmt.Println(len(choke))。如果取消注释,程序将完美运行并且不会阻塞。不会用 print 锁定和解锁通道只会占用 CPU 更多,甚至更早地阻塞程序。 -
这里有一个惯用的解决方案,可以在不阻塞 goroutine 的情况下确定通道是否已满:stackoverflow.com/questions/48939522/…
标签: go concurrency channels