我有两个 channel ,上游和下游。我的目标是从上游读取数据并将其传递给下游。但是,当取消上下文时,我希望在没有死锁的情况下正常退出。
我试图变得“聪明”,并做了类似以下的事情。
func main() {
upstream := make(chan struct{})
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-time.After(5 * time.Second)
cancel()
}()
// Buffered downstream ensures no blocking in this scenario
downstream := make(chan struct{}, 1)
select {
case <-ctx.Done():
log.Println("context is killed")
case downstream <- <-upstream:
log.Println("transferred value from upstream to downstream")
}
}
然后我陷入僵局。但是,如果我不再懒惰并执行以下操作,
func main() {
upstream := make(chan struct{})
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-time.After(5 * time.Second)
cancel()
}()
// Buffered downstream ensures no blocking in this scenario
downstream := make(chan struct{}, 1)
select {
case <-ctx.Done():
log.Println("context is killed")
case val := <-upstream:
downstream <-val
log.Println("transferred value from upstream to downstream")
}
}
它退出时完全正常,没有死锁。您能启发我吗,两者之间的主要区别是什么
downstream <- <-upstream
和
val := <-upstream
downstream <-val
最佳答案
select语句不在<-upstream
接收语句上运行,它在downstream <-
发送语句上运行。
在select案例可以确定downstream <-
send语句是否准备就绪之前,它首先必须评估参数表达式<-upstream
。因为什么都没有发送给upstream
,所以该评估被阻止。这意味着您根本不会涉及选择的案例。
等效的多行代码如下所示,这使得为什么不起作用非常明显。
val := <-upstream
select {
case <-ctx.Done():
log.Println("context is killed")
case downstream <- val:
log.Println("transferred value from upstream to downstream")
}
关于go - 为什么以下 channel 操作会死锁?即下游<-<-上游,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60553980/