为啥程序会在select中被频道阻塞?

Posted

技术标签:

【中文标题】为啥程序会在select中被频道阻塞?【英文标题】:Why the program blocks by the channel in the select?为什么程序会在select中被频道阻塞? 【发布时间】:2022-01-02 15:25:17 【问题描述】:
package main

import (
    "fmt"
)

type A struct
    exit chan bool


func (a *A) f()
    select
        //the routine process

        //quit
        case <- a.exit:

                fmt.Println("-----over-----")
                a.exit <- true
                fmt.Println("+++++over++++++")              
        


func main() 

    a := A
    
    go a.f()
    a.exit = make(chan bool)
    
    a.exit <- true

我想运行多个 goroutine,我想让 main func 注意到其他 goroutine 退出。 这是我的代码,但是选择中的程序块,程序只输出“-----over-----”,没有“+++++over++++++”,代码有什么问题?感谢您帮助。

【问题讨论】:

把“a.exit = make(chan bool)”改成“a.exit = make(chan bool,1)”就好了 【参考方案1】:

您的程序阻塞,因为这是您编写的,请考虑以下操作顺序:

    main goroutine 启动 a.f goroutine。 a.f 阻止尝试从 nil 通道 a.exit 读取。 maina.exit 设置为无缓冲通道,a.f 现在被阻止从新通道读取,这是允许的。 maina.exit 写入一个值,a.fa.exit 读取值,这会同步 goroutines,现在下界被阻塞。 a.f 现在阻止尝试写入无缓冲的a.exit,这将永远不会解除阻止,因为没有人会再次尝试从通道读取。 main 现在退出并导致所有其他 goroutine 退出,这可能发生在第 5 步之前。

所以你的程序从不输出+++++over++++++的原因是:

您的 a.f goroutine 在 a.exit &lt;- true 处阻塞,因为没有其他 goroutine 会从通道中读取此值。 您的main goroutine 可能会在a.f 完成工作之前退出并终止整个程序。

我想你是在问如何在 goroutine 完成后让 main 退出,这是最简单的例子:

package main

import (
    "fmt"
)

type A struct 
    exit chan struct


func (a *A) f() 
    defer close(a.exit) // Close the chanel after f() finishes, closed channels yield the zero-value so <-a.exit will unblock

    fmt.Println("+++++over++++++")


func main() 
    a := A
    go a.f()
    a.exit = make(chan struct)

    <-a.exit

【讨论】:

非常感谢。我知道代码有什么问题,实际上无缓冲通道和大小为 1 的通道之间存在一些差异。在我的程序中,我这样写是因为我想运行很多af(),所以我想如果 af() 停止,它仍然会向 a.exit 通道发送一些信息,以通知其他 af() 到 quit(),所以如果我仍然想使用无缓冲通道,我可能需要添加一个 read主要功能中的频道。感谢您的帮助,我想我明白为什么它是错误的,我可以在我的代码中做什么。

以上是关于为啥程序会在select中被频道阻塞?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 laravel 广播频道有默认前缀?

Django 频道 - websocket_disconnect 在循环中被调用

为啥 TIdIRC 不能连接到频道?有没有更好的组件?

keycloak,为啥后端频道需要重定向 url

golang [去阻塞频道]与Go#golang,#go,#go channels,#go synchronization,#goroutines,#waitgroups中的频道同步和阻止,

为啥我会收到 IllegalArgumentException:不支持的频道配置?