选择和 context.Context Done 通道

sle*_*ica 3 concurrency channel go

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

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

case results <- result:
}
Run Code Online (Sandbox Code Playgroud)

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

关于这种方法,我有两个问题:

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

  2. 根据语言参考:

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

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

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

icz*_*cza 6

这个案例:

case <-ctx.Done():
Run Code Online (Sandbox Code Playgroud)

有通讯操作:

<-ctx.Done()
Run Code Online (Sandbox Code Playgroud)

这是来自频道的接收。规格:接收操作员:

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

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

如果上下文被取消时另一个case( results <- result) 也可以继续,则随机选择一个(伪),无法保证它会是哪一个。

如果你不想上发送值results上下文是否已经取消,检查ctx.Done()通道select另一非阻塞select

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

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

case results <- result:
}
Run Code Online (Sandbox Code Playgroud)

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

查看相关问题:

go select语句的强制优先级

当涉及多个渠道时,选择如何工作?

  • 第一个“select”有助于如果上下文已取消,您将不会尝试在“results”上发送值。否则,如果执行“select”时上下文已被取消,则无法保证在两者都准备好继续时选择哪种情况。 (2认同)