go - 为什么以下 channel 操作会死锁?即下游<-<-上游

标签 go concurrency

我有两个 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/

相关文章:

go - 如何解码嵌套的未知字段

google-app-engine - 静态页面在 Google App Engine 中返回 404

multithreading - 有自动并行的序言实现吗?

iphone - 如何以安全的方式在后台线程中执行文件导入?如何在后台进行安全的文件 I/O 事务?

golang slice [ :] matches with the last element

go - 如何反转 golang map 中项目的顺序?

android-ndk - 是否可以使用带有 cgo 和/或 SWIG 或类似工具的 NDK 在 Go 中构建 Android 游戏?

database - Lost Update 会发生在 PostgreSQL 的读提交隔离级别吗?

java - wait/notifyAll 未按预期工作

ASP.NET 后台工作线程