【问题标题】:Do the 'done' channel and default case lead to goroutine leak'done' 通道和默认情况是否会导致 goroutine 泄漏
【发布时间】:2023-03-17 02:05:01
【问题描述】:

我想和你比较两个类似的案例——唯一的区别是处理值生成的方式

  • 第一种情况:选择一种情况下的值生成
package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    generateValues := func(done <-chan interface{}) <-chan int {
        values := make(chan int)
        go func() {
            defer fmt.Println("All values generated")
            defer close(values)
            for {
                select {
                case <-done:
                    fmt.Println("DONE")
                    return
                case values <- rand.Int():
                    fmt.Println("Generated")
                }

            }

        }()
        return values
    }

    done := make(chan interface{})
    values := generateValues(done)

    for i := 0; i < 3; i++ {
        fmt.Printf("Received value: %v\n", <-values)
    }
    fmt.Println("Closing the channel")
    close(done)
    time.Sleep(5 * time.Second)
}

去游乐场:https://go.dev/play/p/edlOSqdZ9ys

  • 第二种情况:默认情况下的值生成
package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    generateValues := func(done <-chan interface{}) <-chan int {
        values := make(chan int)
        go func() {
            defer fmt.Println("All values generated")
            defer close(values)
            for {
                select {
                case <-done:
                    fmt.Println("DONE")
                    return
                default:
                    values <- rand.Int()
                    fmt.Println("Generated")
                }

            }

        }()
        return values
    }

    done := make(chan interface{})
    values := generateValues(done)

    for i := 0; i < 3; i++ {
        fmt.Printf("Received value: %v\n", <-values)
    }
    fmt.Println("Closing the channel")
    close(done)
    time.Sleep(5 * time.Second)
}

去游乐场:https://go.dev/play/p/edlOSqdZ9ys

如您所见,第二种情况似乎导致未打印“完成”并且未调用与“延迟”相关的调用的情况。我相信我们这里有 goroutine 泄漏,但无法清楚地解释它。我期待与第一种情况相同的行为。

有人可以帮助理解它们之间的区别吗?

【问题讨论】:

    标签: go select default channel goroutine


    【解决方案1】:

    在第二种情况下,生成的 goroutine 不太可能收到done 消息。由于default 的情况总是启用的,所以在主goroutine 收到最后一个值后,生成的goroutine 会进行另一轮,陷入default 情况,并阻塞等待写入values 通道。当它在那里等待时,主 goroutine 关闭 done 通道并终止。

    这并不意味着不存在生成 goroutine 不接收 done 通道的执行路径。为此,在发送最后一个值后,生成的 goroutine 必须被运行的主 goroutine 抢占,直到它关闭 done 通道。然后如果生成的 goroutine 被调度,它可以接收到done 信号。然而,这一系列事件的可能性极小。

    【讨论】:

    • 感谢您的精彩解释!我相信我完全忘记了名为“values”的通道被阻塞的事实,因为主 goroutine 停止了侦听(读取)。
    猜你喜欢
    • 2018-02-23
    • 1970-01-01
    • 2016-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多