通道是否发送抢占点以进行goroutine调度?

huangapple go评论82阅读模式
英文:

Are channel sends preemption points for goroutine scheduling?

问题

根据我对Go调度器的理解,Go调度算法是部分抢占式的:当一个goroutine在调用函数或者在进行I/O阻塞时,会发生goroutine的切换。

在向通道发送消息时,是否会发生goroutine的切换呢?

// goroutine A
ch <- message
// some additional code without function calls

// goroutine B
message := <- ch

在上面的代码中,我希望在A执行完ch <- message后再切换到B,这是有保证的吗?还是在A向ch发送消息后立即切换到B?

英文:

From my understanding of Go scheduler, Go scheduling algorithm is partially preemptive: goroutine switches happen when a goroutine is calling a function or blocking on I/O.

Does a goroutine switch happen when sending a message to a channel?

// goroutine A
ch &lt;- message
// some additional code without function calls

// goroutine B
message := &lt;- ch

In the code above, I want the code after ch &lt;- message in A to be executed before switching to B, is this guaranteed? or does B get scheduled right after A sends a message on ch?

答案1

得分: 7

A的通道发送可以被阻塞,在这种情况下,它会让出调度器,并且你无法保证A何时会再次获得控制权。它可能会在B中你感兴趣的代码之后才执行。因此,即使在GOMAXPROCS=1的情况下,示例代码也存在问题。

回顾一下:抢占发生的时间是一个实现细节;它在过去已经发生过变化(在函数调用时并不总是有抢占的机会),并且将来可能会发生变化。根据内存模型,如果你的程序依赖于关于代码执行时间的事实,而这些事实今天可能是正确的,但并不被保证,那么你的程序是不正确的。如果你想阻塞B中的某些代码直到A执行某些操作,你需要找到一种使用通道或sync原语来安排的方法。

正如用户JimB所指出的,即使不考虑抢占,你在示例代码中也可能遇到问题。A和B可以同时在不同的CPU核上运行,而B中接收后的代码可能会在A中发送后的代码正在运行时运行。

英文:

A's channel send can block, at which point it yields to the scheduler and you have no guarantee when A will receive control again. It might be after the code you're interested in in B. So the sample code has problems even with GOMAXPROCS=1.

Stepping back: when preemption happens is an implementation detail; it has changed in the past (there wasn't always a chance of preemption on function call) and may change in the future. In terms of the memory model, your program is incorrect if it relies on facts about when code executes that happen to be true today but aren't guaranteed. If you want to block some code in B from running until A does something, you need to figure out a way to arrange that using channels or sync primitives.

And as user JimB notes, you don't even need to consider preemption to run into problems with the sample code. A and B could be running simultaneously on different CPU cores, and the code after the receive in B could run while the code after the send in A is running.

答案2

得分: 1

根据我的实际理解,语言和运行时环境的特性告诉我,在显式地在ch <- message之后、调用goroutine B之前没有进行阻塞的情况下,你无法保证A会在B之前完成或运行。我不知道这是如何实现的,但我也不关心,因为我接受了goroutine的抽象概念。不要依赖程序中的巧合功能。根据你的示例,我的建议是将一个通道传递给goroutine A,并在其上进行阻塞等待以串行化A和B的执行。

英文:

My practical understanding of the language and runtime says that without you blocking explicitly after ch &lt;- message and before invoking goroutine B, you have no guarantees that A will complete or run before B. I don't know how that is actually implemented but I also don't care because I accept the goroutine abstraction at face value. Don't rely on coincidental functionality in your program. Just going off your example, my recommendation would be to pass a channel into goroutine A and then block waiting to receive off it in order to serialize A and B.

huangapple
  • 本文由 发表于 2015年12月10日 09:47:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/34192352.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定