channel是否发送抢占点用于goroutine调度?

Are channel sends preemption points for goroutine scheduling?

根据我对 Go scheduler 的理解,Go 调度算法是 partially preemptive:goroutine 切换发生在 goroutine 调用函数或阻塞 I/O。

向频道发送消息时是否发生 goroutine 切换?

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

// goroutine B
message := <- ch

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

A​​ 的通道发送可能会阻塞,此时它会屈服于调度程序,并且您无法保证 A 何时会再次获得控制权。它可能在您对 B 感兴趣的代码之后。因此示例代码即使使用 GOMAXPROCS=1.

也有问题

退一步说:什么时候发生抢占是一个实现细节;它在过去发生过变化(并不总是有机会抢占函数调用)并且将来可能会发生变化。就 memory model 而言,如果您的程序依赖于关于代码何时执行的事实,而这些事实在今天恰好是正确的但不能保证。如果您想从 运行ning 开始阻止 B 中的某些代码,直到 A 执行某些操作,您需要找到一种使用通道或 sync 基元进行安排的方法。

正如用户 JimB 所说,您甚至不需要考虑抢占 运行 示例代码的问题。 A 和 B 可以在不同的 CPU 内核上同时 运行ning,B 中接收后的代码可以 运行 而 A 中发送后的代码是 运行ning .

我对语言和 运行time 的实际理解是,如果你在 ch <- message 之后和调用 goroutine B 之前显式阻塞,你无法保证 A 会完成或 运行在 B 之前。我不知道它实际上是如何实现的,但我也不在乎,因为我从表面上接受 goroutine 抽象。不要依赖程序中巧合的功能。就你的例子而言,我的建议是将一个通道传递给 goroutine A,然后阻塞等待接收它以序列化 A 和 B。