深入理解 Go 语言并发编程之系统调用底层原理
用户协程是如何执行系统调用的?系统调用有可能会阻塞线程 M,如果所有的线程 M 都因系统调用阻塞了,这时候谁来调度协程呢?
1. 系统调用会阻塞线程吗
系统调用会阻塞线程吗?在这回答这个问题之前,我们先模拟一个 Go 程序执行阻塞式系统调用的情况。
第一个程序就是普通的 Go 程序,没有执行任何系统调用,代码如下所示:
package main
import (
"runtime"
"time"
)
func main() {
//设置逻辑处理器 P 的数目为 4
runtime.GOMAXPROCS(4)
//创建 10 个用户协程
for i := 0; i < 10; i++ {
go func() {
for {
}
}()
}
time.Sleep(time.Second * 1000)
}
上面的 Go 程序非常简单,本身没有任何意义,只是显式地设置逻辑处理器 P 的数目为 4,随后创建了多个用户协程。
参考上面的结果,Go 程序总共创建了 5 个子线程,暂时记录下这个结果,待会和第二个程序的输出做一个对比。当然,你可能会好奇为什么实际的线程数大于逻辑处理器 P 的数目,这里我们大不必纠结背后的原因(Go 语言还会创建辅助线程)。
第二个程序会执行一些阻塞式的系统调用,代码如下所示:
package main
import (
"net"
"runtime"
"syscall