首页  >  文章  >  后端开发  >  为什么 Go 通道会导致死锁以及我们如何预防它们?

为什么 Go 通道会导致死锁以及我们如何预防它们?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-11-02 09:50:03394浏览

Why Do Go Channels Cause Deadlocks and How Can We Prevent Them?

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中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn