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

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 <- message
// some additional code without function calls

// goroutine B
message := <- ch

In the code above, I want the code after ch <- 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?

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.

My practical understanding of the language and runtime says that without you blocking explicitly after ch <- 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.