【问题标题】:select and context.Context Done channel选择和上下文。上下文完成通道
【发布时间】:2021-03-18 05:11:20
【问题描述】:

我不明白context.Context 中的Done() 频道如何按预期工作。模块文档(以及使用它的源代码)依赖于这种模式:

select {
case <-ctx.Done():
    return ctx.Err()

case results <- result:
}

如果Context被取消或超时,Done()的通道返回关闭,Err()变量保存原因。

我对这种方法有两个问题:

  1. 当频道关闭时select 的行为是什么?何时以及为何进入案件?没有分配的事实是否具有相关性?

  2. 根据语言参考:

    如果一个或多个通信可以继续,则通过统一的伪随机选择选择一个可以继续的通信。

    如果选择是随机的,那么当Context 被取消时,该模式如何保证我不会将结果发送到管道中?如果这些案例是按申报顺序评估的(并且选择了封闭渠道案例),我会理解。

如果我在这里完全偏离轨道,请从更好的角度向我解释。

【问题讨论】:

  • “该模式如何保证我不会将结果发送到管道中?”,没有任何模式可以,这就是并发的本质。
  • 您可以对“该模式如何保证我不会通过管道发送结果”有一些保证:这取决于您如何创建result。如果result 没有缓冲,则只有在某些接收操作解决后,发送操作才会继续。如果result 有一个缓冲区,它可能包含一个(或多个)值;但是,如果在您的 select 语句中执行的分支是 &lt;-ctx.Done() : 之一,您仍然可以保证不会从 result 中弹出任何值。
  • 除非它可能在发送之前被取消,或者在您检查缓冲通道后准备发送。截止时间总是任意的,如果您不等待响应,您只需要接受您可能会“接近”,这并不重要。

标签: go concurrency channel


【解决方案1】:

这个案例:

case <-ctx.Done():

有通讯操作:

<-ctx.Done()

这是来自频道的接收。 Spec: Receive operator:

closed 通道上的接收操作总是可以立即进行,在接收到任何先前发送的值之后产生元素类型的 zero value

因此,当ctx.Done() 返回的通道关闭时,来自它的接收可以立即进行。因此控制流可以进入这种情况。

如果另一个case (results &lt;- result) 在上下文被取消时也可以继续,则随机选择(伪)一个,不能保证会是哪一个。

如果您不想在上下文已取消的情况下在results 上发送值,请检查ctx.Done() 频道之前 select另一个 非阻塞select:

select {
case <-ctx.Done():
    return ctx.Err()
default:
}

select {
case <-ctx.Done():
    return ctx.Err()

case results <- result:
}

请注意,您必须将default 分支添加到第一个选择,否则它将阻塞直到上下文被取消。如果存在default 分支并且上下文尚未取消,则选择default 分支,因此控制流可以转到第二个select

查看相关问题:

Force priority of go select statement

How does select work when multiple channels are involved?

【讨论】:

  • 我不确定我是否理解第一个 select 有何帮助。如果不同线程中的另一个例程关闭了语句之间的通道,我是不是处于同样的情况?
  • 第一个select 有助于如果上下文已被取消,您将不会尝试在results 上发送值。否则,如果在执行select 时上下文已经取消,则无法保证如果两者都准备好继续,则选择哪种情况。
猜你喜欢
  • 2019-06-17
  • 2014-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-04
  • 2011-03-25
  • 2021-10-14
相关资源
最近更新 更多