将通道从无缓冲更改为缓冲会阻止 goroutine 运行

这是一个在 goroutine 中使用通道和选择的练习。如果断开连接通道更改为缓冲通道,则 goroutine 根本不会运行。


为什么从无缓冲通道更改为缓冲通道会阻止运行 goroutine?


func SelectDemo(wg *sync.WaitGroup) {


    messageCh := make(chan int, 10)

    disconnectCh := make(chan struct{})

    //  go routine won't run if channel is buffered

    //disconnectCh := make(chan struct{}, 1)


    defer close(messageCh)

    defer close(disconnectCh)

    go func() {

        fmt.Println("  goroutine")

        wg.Add(1)

        for {

            select {

            case v := <-messageCh:

                fmt.Println(v)

            case <-disconnectCh:

                fmt.Println("  disconnectCh")

                //  empty the buffered channel before exiting

                for {

                    select {

                    case v := <-messageCh:

                        fmt.Println(v)

                    default:

                        fmt.Println("  disconnection, return")

                        wg.Done()

                        return

                    }

                }

            }

        }

    }()


    fmt.Println("Sending ints")

    for i := 0; i < 10; i++ {

        messageCh <- i

    }


    fmt.Println("Sending done")

    disconnectCh <- struct{}{}

}

这是从 main 调用函数的代码。我使用等待组来确保 goroutine 在程序退出之前完成:


wg := sync.WaitGroup{}

ch09.SelectDemo(&wg)

wg.Wait()


动漫人物
浏览 74回答 2
2回答

一只萌萌小番薯

该代码逻辑有许多缺陷 - 其中一些是:1- 由于messageCh被缓冲,此代码没有阻塞:&nbsp; &nbsp; for i := 0; i < 10; i++ {&nbsp; &nbsp; &nbsp; &nbsp; messageCh <- i&nbsp; &nbsp; }所以下一个代码在快速运行路径中:disconnectCh <- struct{}{}如果您进行disconnectCh缓冲,则此行也不会阻塞运行,并且该SelectDemo函数可能会在运行wg.Add(1).所以:你必须把:wg.Add(1)前go func() {2-即使使用wg.Add(1)之前的go func() { 代码-您也有:&nbsp; &nbsp; defer close(messageCh)&nbsp; &nbsp; defer close(disconnectCh)这将在函数返回时关闭两个通道SelectDemo这select是一个随机选择,因为两个通道都准备好了:fmt.Println("&nbsp; goroutine")&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case v := <-messageCh:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(v)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-disconnectCh:第二个选择很可能是:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case v := <-messageCh:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(v)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("&nbsp; disconnection, return")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }将在messageCh关闭后0永远运行,在读取通道数据后永远返回:case v := <-messageCh:&nbsp; &nbsp; fmt.Println(v)

犯罪嫌疑人X

程序执行速度快访问网址:https ://pkg.go.dev/sync#WaitGroup.Add请注意,当计数器为零时发生的具有正增量的调用必须在等待之前发生。具有负增量的调用或具有正增量的调用在计数器大于零时开始,可能随时发生。通常这意味着对 Add 的调用应该在创建 goroutine 的语句或其他要等待的事件之前执行。如果重用 WaitGroup 来等待多个独立的事件集,则必须在所有先前的 Wait 调用都返回后发生新的 Add 调用。请参阅 WaitGroup 示例。func SelectDemo(wg *sync.WaitGroup) {&nbsp; &nbsp; messageCh := make(chan int, 10)&nbsp; &nbsp; disconnectCh := make(chan struct{}, 1)&nbsp; &nbsp; //&nbsp; go routine won't run if channel is buffered&nbsp; &nbsp; //disconnectCh := make(chan struct{}, 1)&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; defer close(messageCh)&nbsp; &nbsp; defer close(disconnectCh)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("&nbsp; goroutine")&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case v := <-messageCh:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(v)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-disconnectCh:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("&nbsp; disconnectCh")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; empty the buffered channel before exiting&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("&nbsp; disconnection, return")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()&nbsp; &nbsp; fmt.Println("Sending ints")&nbsp; &nbsp; for i := 0; i < 10; i++ {&nbsp; &nbsp; &nbsp; &nbsp; messageCh <- i&nbsp; &nbsp; }&nbsp; &nbsp; //Delay sending exit signal&nbsp; &nbsp; time.Sleep(3 * time.Second)&nbsp; &nbsp; fmt.Println("Sending done")&nbsp; &nbsp; disconnectCh <- struct{}{}}我修改了你的代码再试一次!!!
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go