英文:
Go <-chan overhead
问题
我一直在努力理解Go语言中的通道。但有一件事让我感到疑惑。当你调用以下代码时会发生什么?
for {
select {
case <-chan:
}
}
它会在每次迭代中检查通道是否有更新吗?从性能上来说,它与普通的case i = int:
或case atomic.LoadUint64() = uint64:
有何区别?
英文:
I have been trying to understand channels in Go for a while now. But one thing makes me wonder. What happens exactly when you call,
for {
select {
case <-chan:
}
}
Does it check the chan every for iteration for updates? How would it compare to a normal case i = int:
, or a case atomic.LoadUint64() = uint64:
performance-wise?
答案1
得分: 3
《Go编程语言规范》中定义了Go的select
语句的行为。在进入select
语句时,对于语句中的所有情况,接收操作的通道操作数以及发送语句的通道和右侧表达式将按照源代码顺序进行精确一次的评估。
如果其中一个或多个通信可以进行,则通过均匀的伪随机选择选择一个可以进行的通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,则select
语句将阻塞,直到至少有一个通信可以进行。
除非所选情况是默认情况,否则将执行相应的通信操作。如果所选情况是具有短变量声明或赋值的RecvStmt
,则将评估左侧表达式并分配接收到的值(或值)。然后执行所选情况的语句列表。
<-chan
在select
语句进入时进行一次评估。
你可以在《Go编程语言规范》中了解更多信息。
英文:
> 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.
Go select
statement behavior is defined in The Go Programming Language Specification. <-chan
is evaluated once.
> 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.
答案2
得分: 2
通道的实现没有被语言规范定义(也永远不会定义),所以特定的实现可以自由地做任何事情,只要符合规范即可。
另一方面,访问通道的行为类似于访问互斥锁,因此我认为在内部,Go会安排使用系统提供的方法来阻塞在适当的资源上。可以想象在Windows上使用WaitForMultipleObjects()
,在Linux上使用futex等。
换句话说,虽然for { select { case <-chan: ... } }
的结构看起来像是对这些case
标签中的对象进行忙等待,但实际上并不是这样:编译器利用系统的方式,使得Go运行时调度器在某些资源可用时被通知。
英文:
The implementation of channels is not defined by the language specification (and will never be), so a particular implementation is free to do anythng it wants while it conforms to the specification.
On the other hand, accessing a channel behaves like accessing a mutex so I beleive internally Go arranges to use system-provided means of blocking on an appropriate resource. Think of WaitForMultipleObjects()
on Windows, futexes on Linux and so on.
In other words, while the for { select { case <-chan: ... } }
construct looks like busy waiting on the objects in those case
labels, in fact it is not: the compiler leverages the system's means of making the Go runtime scheduler be notified when some of those resources becomes available.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论