操作系统可以看作是个虚拟机(VM),进程生活在操作系统创造的虚拟世界里。进程不用知道到底有多少 core 多少内存,只要进程不要索取的太过分,操作系统就假装有无限多的资源可用。
基于这个思想,线程(Thread)的个数并不受硬件限制:你的程序可以只有一个线程、也可以有成百上千个。操作系统会默默做好调度,让诸多线程共享有限的 CPU 时间片。这个调度的过程对线程是完全透明的。
那么,操作系统是怎样做到在线程无感知的情况下调度呢?答案是上下文切换(Context Switch),简单来说,操作系统利用软中断机制,把程序从任意位置打断,然后保存当前所有寄存器——包括最重要的指令寄存器 PC 和栈顶指针 SP,还有一些线程控制信息(TCB),整个过程会产生数个微秒的 overhead。
然而作为一位合格的程序员,你一定也听说过,线程是昂贵的:
线程的上下文切换有不少的代价,占用宝贵的 CPU 时间;
每个线程都会占用一些(至少 1 页)内存。
这两个原因驱使我们尽可能避免创建太多的线程,而异步编程的目的就是消除 IO wait 阻塞——绝大多数时候,这是我们创建一堆线程、甚至引入线程池的罪魁祸首。