在 Go 语言中,每个 goroutine 都会被分配一个固定的时间片,当时间片用完后,调度器会暂停当前 goroutine,切换到其他 goroutine 上执行。这种机制被称为抢占式调度,因为调度器可以在任何时候抢占当前 goroutine 的执行,并将 CPU 时间片分配给其他 goroutine。
抢占式调度有以下几个特点:
下面是一个示例代码,演示了抢占式调度的效果:
package main
import (
"fmt"
"runtime"
)
func main() {
runtime.GOMAXPROCS(1) // 限制只使用一个 CPU 核心
go func() {
for i := 0; i < 10; i++ {
fmt.Println("goroutine 1:", i)
}
}()
go func() {
for i := 0; i < 10; i++ {
fmt.Println("goroutine 2:", i)
}
}()
// 等待 goroutine 执行完毕
var input string
fmt.Scanln(&input)
}
在上面的示例代码中,我们通过调用 runtime.GOMAXPROCS(1) 来限制程序只使用一个 CPU 核心。然后我们启动了两个 goroutine,分别打印数字,由于只有一个核心,所以两个 goroutine 会交替执行,输出结果可能类似于下面这样:
goroutine 1: 0
goroutine 1: 1
goroutine 2: 0
goroutine 1: 2
goroutine 2: 1
goroutine 1: 3
goroutine 2: 2
goroutine 1: 4
goroutine 2: 3
goroutine 1: 5
goroutine 2: 4
goroutine 1: 6
goroutine 2: 5
goroutine 1: 7
goroutine 2: 6
goroutine 1: 8
goroutine 2: 7
goroutine 1: 9
goroutine 2: 8
goroutine 2: 9
可以看到,两个 goroutine 交替执行,输出结果不是确定的。这就是抢占式调度的特点。