Golang调度器原理解析
本文主要介绍调度器的由来以及golang调度器为何要如此设计,以及GPM模型解析
一.调度器的由来
1.单进程时代
单进程时代不需要调度器,一切程序都是串行,所以单进程的操作系统会面临这样一个问题:
- 程序只能串行执行,一个进程阻塞了,其他进程啥事也做不了,只能等待,会造成CPU时间的严重浪费
那么能不能有多个进程一起来执行多个任务呢?
答案是可以的,后来操作系统就有了最早的并发能力:多进程并发多进程并发:当一个进程阻塞的时候,切换到另外等待执行的进程,尽量将CPU利用起来。
2.多进程/多线程时代
多进程或多线程时代就有了调度器的需求,以多进程为例,其会使用CPU调度器来当某个进程阻塞的时候,调度一个合适的进程给CPU。
这种方式解决了阻塞的问题,但也存在一个问题:
- 如果进程数量很多,进程的调度会占用CPU很多的时间(进程创建,销毁,切换等),CPU利用率不高
对比线程,虽然其调度成本会比进程小很多,但实际上多线程程序的开发和设计也比较复杂,而且在当前互联网业务环境下,为每个任务都创建一个线程是不现实的,这会大量的消耗内存(进程占用4G(32位),而线程大约也要4M)
所以,多线程/多进程时代,会面临这样两个问题
- 高内存占用
- 调度的高CPU消耗
但是,其实一个线程可以分为内核态线程和用户态线程,一个用户态线程必须要绑定一个内核态线程,但是CPU并不知道用户态线程的存在,它只知道它运行的是一个内核态线程(Linux的PCB进程控制块)