问题描述
作为一个愚蠢的基本线程练习,我一直在试图实现在golang。有渠道这应该是很容易,但我遇到了一个heisenbug。也就是说,当我尝试诊断它时,问题就消失了!
As a silly basic threading exercise, I've been trying to implement the sleeping barber problem in golang. With channels this should be quite easy, but I've run into a heisenbug. That is, when I try to diagnose it, the problem disappears!
请考虑以下内容。 main()
函数将整数(或customers)推送到商店
通道。 barber()
读取商店
频道以剪切客户的头发。如果我在 customer()
函数中插入 fmt.Print
语句,程序将按预期运行。
Consider the following. The main()
function pushes integers (or "customers") onto the shop
channel. barber()
reads the shop
channel to cut "customers'" hair. If I insert a fmt.Print
statement into the customer()
function, the program runs as expected. Otherwise, barber()
never cuts anyone's hair.
package main
import "fmt"
func customer(id int, shop chan<- int) {
// Enter shop if seats available, otherwise leave
// fmt.Println("Uncomment this line and the program works")
if len(shop) < cap(shop) {
shop <- id
}
}
func barber(shop <-chan int) {
// Cut hair of anyone who enters the shop
for {
fmt.Println("Barber cuts hair of customer", <-shop)
}
}
func main() {
shop := make(chan int, 5) // five seats available
go barber(shop)
for i := 0; ; i++ {
customer(i, shop)
}
}
推荐答案
问题是Go的调度器是如何实现的。只有当进行系统调用或阻塞通道操作时,当前goroutine才能对其他goroutine产生。 fmt.Println
进行系统调用,使goroutine有机会产生。
The problem is the way Go's scheduler is implemented. The current goroutine can yield to other goroutines only when it makes a system call or a blocking channel operation. fmt.Println
makes a system call, giving the goroutine an opportunity to yield. Otherwise it doesn't have one.
在实践中,这通常并不重要,但对于像这样的小问题,它有时会出现。
In practice this doesn't often matter, but for small problems like this it can sometimes crop up.
此外,在频道上进行非阻塞发送的一种更为惯用的方法是:
Also, a more idiomatic, less racy way of doing a non-blocking send on a channel is:
func customer(id int, shop chan<- int) {
// Enter shop if seats available, otherwise leave
select {
case shop <- id:
default:
}
}
,客户可能最终在理发店外等待,因为在您实际发送发件时, len(shop)
可能已更改。
The way you're doing it, a customer could end up waiting outside of the barber shop since by the time you actually do the send, len(shop)
may have changed.
这篇关于打印到stdout导致阻止goroutine运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!