Go 通道和死锁:了解阻塞问题
使用 Go 通道时,如果不能确保正确的同步,可能会出现死锁。考虑以下示例:
<code class="go">func main() { c1 := make(chan int) c2 := make(chan int) // Create two goroutines that ping-pong values between channels go func() { for i := range c1 { println("G1 got", i) c2 <- i } }() go func() { for i := range c2 { println("G2 got", i) c1 <- i } }() // Send an initial value to start the chain c1 <- 1 // Wait for a long time to observe the ping-ponging behavior time.Sleep(1000000000 * 50) }</code>
此代码成功地无限期地打印值,直到主函数退出。但是,如果将另一个值发送到其中一个通道,则会发生死锁:
<code class="go">func main() { c1 := make(chan int) c2 := make(chan int) // Create two goroutines to ping-pong values between channels go func() { for i := range c1 { println("G1 got", i) c2 <- i } }() go func() { for i := range c2 { println("G2 got", i) c1 <- i } }() // Send an initial value to start the chain c1 <- 1 // Wait for a short time time.Sleep(1000000000 * 1) // Send another value to the channel c1 <- 2 // Wait for a long time to observe the issue time.Sleep(1000000000 * 50) }</code>
在这种情况下,发送值“2”后输出会卡住:
G1 got 1 G2 got 1 G1 got 1 G2 got 1 G1 got 2
出现此问题是因为 goroutine 正在等待彼此从各自的通道接收值。因此,两个 goroutine 都无法进行,就会发生死锁。
为了防止死锁,请确保通道正确同步。一种方法是使用容量非零的缓冲通道,如下例所示:
<code class="go">// ... (Same code as before) c1 := make(chan int, 1) // Buffered channel with capacity of 1 c2 := make(chan int, 1)</code>
使用缓冲通道,一个 goroutine 可以发送一个值,即使另一个 goroutine 尚未收到前一个值一。这有助于避免在上述情况下出现死锁。
以上是为什么 Go 通道会导致死锁以及我们如何预防它们?的详细内容。更多信息请关注PHP中文网其他相关文章!