这是Golang的一个示例代码。但是不明白为什么在这种情况下需要“完成”通道。
https://gobyexample.com/closing-channels
没有理由将true发送到已完成通道。当打印“发送所有作业”消息时,我们可以知道作业通道已完成,不是吗?
我删除了与完成通道相关的代码,结果仍然相同。
https://play.golang.org/p/xOmzobFpTQ
这是Golang的一个示例代码。但是不明白为什么在这种情况下需要“完成”通道。
https://gobyexample.com/closing-channels
没有理由将true发送到已完成通道。当打印“发送所有作业”消息时,我们可以知道作业通道已完成,不是吗?
我删除了与完成通道相关的代码,结果仍然相同。
https://play.golang.org/p/xOmzobFpTQ
4条答案
按热度按时间p4tfgftt1#
不,结果是不一样的:
在很多情况下(例如,不同的CPU负载,以及它是不确定的和系统相关的行为),你的主goroutine会在你的
received job
goroutine之前退出,所以在这种情况下你不能保证all jobs received
,例如just Add之前
要看到这一点,请在The Go Playground上尝试:
输出:
而不是:
参见:
Goroutine does not execute if time.Sleep included
Why is time.sleep required to run certain goroutines?
Weird channel behavior in go
fjnneemd2#
TL;DR:有一个竞态条件---你很幸运。
如果没有
done
通道,则程序的输出是不确定的。根据线程的执行顺序,主线程可能会在goroutine完成处理之前退出,从而导致goroutine在中途被杀死。
通过强制主线程从
done
通道读取,我们强制主线程等待,直到done
通道中有一些数据需要使用,这给了我们一个简洁的同步机制,goroutine通过向done
通道写入来通知主线程它已经完成,这反过来又导致主线程's阻止<- done
完成并导致程序终止。vbopmzt13#
Go语言属于过程化范式,这意味着每条指令都是线性执行的,当一个Go例程从主Go例程分支出来时,它就开始了自己的小冒险,让主线程返回。
缓冲通道的容量为5,这意味着在缓冲区满之前它不会阻塞。如果缓冲区为空,它也会阻塞(容量为零的通道本质上是无缓冲的)。
由于只有4次迭代(0到〈=3),读操作将不会阻塞。
通过指示主线程从done通道读取数据,我们强制主线程等待,直到done通道中有一些数据需要使用。当迭代结束时,else分支被执行,写操作
done <- true
导致主线程中<- done
读操作的释放。读操作等待从done
中取出现在插入的值。从
done
阅读后,Go主例程不再被阻塞,因此成功终止。ee7vknir4#