为什么这两段代码执行不同?
fatal error: all goroutines are asleep - deadlock!
错误。func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
fmt.Println(<-ch)
}
ch := make(chan int)
go buffer(ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
func buffer(ch chan int) {
ch <- 2
ch <- 3
}
#1 仅当 ch 被定义为缓冲通道时才能正确执行。为什么?为什么 ch in buffer() 毫无怨言地接受 2 个值?
对无缓冲通道的发送操作将阻塞,直到另一个 goroutine 从中读取。这就是第一段代码死锁的原因:当你发送到通道时,没有其他 goroutines 从它读取。
在第二种情况下,您有一个 goroutine 向通道发送两个值,并且主 goroutine 在发送的同时从通道读取两次。该通道不接受两次发送,它是一个接一个地进行,第一次发送操作被第一次读取解除阻塞,第二次发送操作被第二次读取解除阻塞。
在您的代码示例中,由于只有一个 goroutine(主 goroutine)永远不会到达第 3 和 4 行,因此它有效:
ch := make(chan int)
ch <- 1 // blocks forever - as no one is reading
// fmt.Println(<-ch)
// fmt.Println(<-ch)
通过通道进行的通信旨在跨 goroutines 使用——因为这里只有一个 goroutine,它将永远阻塞。
如您所见,缓冲频道会有所帮助...
ch := make(chan int, 1) // buffer of one
ch <- 1 // works
ch <- 2 // blocks forever
// never reached
// fmt.Println(<-ch)
// fmt.Println(<-ch)
...但是有点做作而且不是很有用。
在你的第二个例子中,这是正确的模式,至少有 2 个 goroutines 合作:
go buffer(ch) // goroutine that writes to the channel
创建一个专门的 writer goroutine,释放主 goroutine 以实时成功读取这些写入中的任何一个:
fmt.Println(<-ch)
fmt.Println(<-ch)