我编写了一些旨在使用 channel 进行同步的代码。
var counter int64 // shared resource
var wg sync.WaitGroup
func main() {
ch := make(chan int64)
wg.Add(2)
go incCounter(ch)
go incCounter(ch)
ch <- counter
wg.Wait()
fmt.Println("Final Counter:", counter) // expected value is 4
}
func incCounter(ch chan int64) {
defer wg.Done()
for count := 0; count < 2; count++ {
value := <-ch
value++
counter = value
ch <- counter
}
}
当我运行该程序时,发生了一个错误:
all goroutines are asleep - deadlock!
。但是我无法解决问题,也不知道出了什么问题。有人可以帮忙吗? 最佳答案
channel make(chan int)
的隐式大小为零(引用:https://golang.org/ref/spec#Making_slices_maps_and_channels)
大小为零的 channel 未缓冲。指定大小的 channel make(chan int,n)被缓冲。有关缓冲 channel 与非缓冲 channel 的讨论,请参见http://golang.org/ref/spec#Send_statements。 http://play.golang.org/p/VZAiN1V8-P上的示例说明了差异。
在这里, channel <-ch
或ch <-
将被阻止,直到有人对其进行处理(同时)。如果您尝试用笔和纸写这个程序的流程,您将弄清楚为什么它被阻塞了。下图显示了可能通过 channel ch
的数据流:
因此,如果将ch := make(chan int64)
设置为ch := make(chan int64,1)
,它将起作用。
var counter int64 // shared resource
var wg sync.WaitGroup
func main() {
ch := make(chan int64, 1)
wg.Add(2)
go incCounter(ch)
go incCounter(ch)
ch <- counter
wg.Wait()
fmt.Println("Final Counter:", counter) // expected value is 4
}
func incCounter(ch chan int64) {
defer wg.Done()
for count := 0; count < 2; count++ {
value := <-ch
value++
counter = value
ch <- counter
}
}
如果我们分析使用
ch := make(chan int64)
时程序的工作方式,我们可以看到此程序中阻塞了一个go例程(退出了另一个例程)。借助time.Sleep(n)
并在阻塞的go例程中从 channel 接收最后的数据,我们可以克服死锁。请参见下面的代码:var counter int64 // shared resource
var wg sync.WaitGroup
func main() {
ch := make(chan int64)
wg.Add(2)
go incCounter(ch)
go incCounter(ch)
ch <- counter
// to ensure one go routine 'incCounter' is completed and one go routine is blocked for unbuffered channel
time.Sleep(3*time.Second)
<-ch // to unblock the last go routine
wg.Wait()
fmt.Println("Final Counter:", counter) // expected value is 4
}
func incCounter(ch chan int64) {
defer wg.Done()
for count := 0; count < 2; count++ {
value := <-ch
value++
counter = value
ch <- counter
}
}
关于go - 所有goroutine都在 sleep ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53169598/