使用 select 语句的程序在 go 中逃脱死锁

Program with select statements escape deadlock in go

这个问题很可能已经被我找不到了,所以我们开始:

我有这个发送或接收 "messages" 的函数,使用 select 语句:

func Seek(name string, match chan string) {
select {
case peer := <-match:
    fmt.Printf("%s sent a message to %s.\n", peer, name)
case match <- name:
    // Wait for someone to receive my message.

我在 4 个不同的 go-routines 上启动这个函数,使用一个无缓冲的通道(最好使用缓冲区 och 1 但这只是实验性的):

people := []string{"Anna", "Bob", "Cody", "Dave"}
match := make(chan string)
for _, name := range people {
    go Seek(name, match, wg)

现在,我刚开始使用 go 并认为由于我们使用的是无缓冲通道,所以 "select" 的发送和接收语句都应该阻塞(没有人在等待发送消息所以你无法接收,也没有人在等待接收,所以你无法发送),这意味着函数之间不会进行任何通信,也就是死锁。然而 运行 代码告诉我们情况并非如此:

API server listening at: 127.0.0.1:48731
Dave sent a message to Cody.
Anna sent a message to Bob.
Process exiting with code: 0

我想问你们这些可爱的人,为什么会这样?编译器是否意识到函数想要在同一个通道中读取/写入并安排它发生?还是 "select" 语句会不断检查是否有人可以使用该频道?

抱歉,如果问题难以回答,我还是个新手,对幕后的运作方式经验不足:)

Now, I've just started using go and thought that since we're using an unbuffered channel, both the send and recieve statement of the "select" should block (there's no one waiting to send a message so you can't recieve, and there's no one waiting to recieve so you can't send)

事实并非如此;事实上,有多个goroutines等待接收和多个goroutines等待发送。当一个 goroutine 像你一样做 select 时:

select {
case peer := <-match:
    fmt.Printf("%s sent a message to %s.\n", peer, name)
case match <- name:
    // Wait for someone to receive my message.

正在同时等待发送和接收。由于您有多个例程执行此操作,因此每个例程都会找到发送者和接收者。什么都不会阻止。 selects会随机选择case,因为多个case同时解封