在 Go 语言中,是如何抢占 P 的呢,这里面是怎么做的?
今天这篇文章我们就来解密抢占 P。
调度器的发展史
在 Go 语言中,Goroutine 早期是没有设计成抢占式的,早期 Goroutine 只有读写、主动让出、锁等操作时才会触发调度切换。
这样有一个严重的问题,就是垃圾回收器进行 STW 时,如果有一个 Goroutine 一直都在阻塞调用,垃圾回收器就会一直等待他,不知道等到什么时候…
这种情况下就需要抢占式调度来解决问题。如果一个 Goroutine 运行时间过久,就需要进行抢占来解决。
这块 Go 语言在 Go1.2 起开始实现抢占式调度器,不断完善直至今日:
- Go0.x:基于单线程的程调度器。
- Go1.0:基于多线程的调度器。
- Go1.1:基于任务窃取的调度器。
- Go1.2 - Go1.13:基于协作的抢占式调度器。
- Go1.14:基于信号的抢占式调度器。
调度器的新提案:非均匀存储器访问调度(Non-uniform memory access,NUMA),
但由于实现过于复杂,优先级也不够高,因此迟迟未提上日程。
有兴趣的小伙伴可以详见 Dmitry Vyukov, dvyukov 所提出的 NUMA-aware scheduler for Go。
为什么要抢占 P
为什么会要想去抢占 P 呢,说白了就是不抢,就没机会运行,会 hang 死。又或是资源分配不均了,
这在调度器设计中显然是不合理的。
跟这个