英文:
Priority of case versus default in golang select statements
问题
我有一个应用程序,其中有多个正在运行for
循环的goroutine,并且需要一种方法来向这些for
循环发送信号以中断,并测试超时情况是否发生。我正在研究使用带有select
语句的共享通道来实现此目的,代码如下:
// 在代码的其他位置,创建此通道,并将其传递给下面的代码
done := make(chan struct{})
time.AfterFunc(timeout, func() { close(done) })
...
go func() {
Loop:
for {
select {
case <-done:
break Loop
default:
foo()
time.Sleep(1 * time.Second)
}
}
select {
case <-done:
panic("超时!")
default:
// 正常情况
}
}()
这种方法有效吗?我最担心的是select
语句选择的分支可能是非确定性的,即使其中一个case
已经准备好,也可能选择default
。这种情况可能发生吗?是否有任何文档说明匹配的case
优先于default
?担心的是,在关闭done
之后,上面的for
循环可能会循环多次和/或报告成功,即使发生了超时。
英文:
I have an application with multiple goroutines that are running for
loops, and need a way to signal these for
loops to break, and to test whether the timeout case occurred. I was looking into using a shared channel with select
statements to accomplish this as follows:
// elsewhere in the code, this channel is created, and passed below
done := make(chan struct{})
time.AfterFunc(timeout, func() { close(done) })
...
go func() {
Loop:
for {
select {
case <-done:
break Loop
default:
foo()
time.Sleep(1 * time.Second)
}
}
select {
case <-done:
panic("timed out!")
default:
// ok
}
}()
Is this a valid way to accomplish this? What I'm most concerned about is that the branch of a select
that is chosen could be non-deterministic, so that default
may be chosen even if one of the case
s is ready. Is this possible? Is there any documentation that states that a matching case
is guaranteed to have preference over a default
. The concern is that the for loop above could loop several times after done
is closed and/or report success even though a timeout occurred.
答案1
得分: 8
《Go编程语言规范》
选择语句的执行分为几个步骤:
- 对于语句中的所有情况,接收操作的通道操作数以及发送语句的通道和右侧表达式在进入选择语句时按照源代码顺序进行精确一次评估。结果是一组要接收或发送的通道,以及要发送的相应值。在该评估中的任何副作用都将发生,无论选择了哪个(如果有)通信操作来继续。具有短变量声明或赋值的RecvStmt左侧的表达式尚未评估。
- 如果一个或多个通信可以继续进行,则通过均匀伪随机选择选择一个可以继续进行的通信。否则,如果有默认情况,则选择该情况。如果没有默认情况,则选择语句将阻塞,直到至少有一个通信可以继续进行。
- 除非所选情况是默认情况,否则将执行相应的通信操作。
- 如果所选情况是具有短变量声明或赋值的RecvStmt,则将评估左侧表达式并分配接收到的值(或值)。
- 执行所选情况的语句列表。
我最关心的是选择语句中选择的分支可能是非确定性的,即使其中一个情况已经准备好,也可能选择默认情况。这种情况是否可能?
不可能。请参考select
规范的第2步。
英文:
> The Go Programming Language Specification
>
> Select statements
>
> Execution of a "select" statement proceeds in several steps:
>
> 1. For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send
> statements are evaluated exactly once, in source order, upon entering
> the "select" statement. The result is a set of channels to receive
> from or send to, and the corresponding values to send. Any side
> effects in that evaluation will occur irrespective of which (if any)
> communication operation is selected to proceed. Expressions on the
> left-hand side of a RecvStmt with a short variable declaration or
> assignment are not yet evaluated.
> 2. If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection.
> Otherwise, if there is a default case, that case is chosen. If there
> is no default case, the "select" statement blocks until at least one
> of the communications can proceed.
> 3. Unless the selected case is the default case, the respective communication operation is executed.
> 4. If the selected case is a RecvStmt with a short variable declaration or an assignment, the left-hand side expressions are
> evaluated and the received value (or values) are assigned.
> 5. The statement list of the selected case is executed.
> "What I'm most concerned about is that the branch of a select that is
> chosen could be non-deterministic, so that default may be chosen even
> if one of the cases is ready. Is this possible?"
No. See step 2 of the select
specification.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论