为什么下面的通道操作会死锁?即下游 <- <- 上游

我有两个渠道,上游和下游。我的目标是从上游读取数据并将它们传递给下游。但是,当上下文被取消时,我想优雅地退出而不会出现死锁。


我试图变得“聪明”并做了类似以下的事情。


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


ITMISS
浏览 99回答 1
1回答

米琪卡哇伊

select 语句不是在<-upstream接收语句上运行,而是在downstream <-send 语句上运行。在选择案例可以确定downstream <-发送语句是否准备好之前,它首先必须评估参数表达式,即<-upstream. 因为没有任何东西被发送到upstream,所以该评估被阻止。这意味着您根本不会接触到选定的案例。等效的多行代码看起来像这样,这很明显为什么它不起作用。val := <-upstreamselect {case <-ctx.Done():&nbsp; &nbsp; log.Println("context is killed")case downstream <- val:&nbsp; &nbsp; log.Println("transferred value from upstream to downstream")}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go