进程是资源分配的最小单位,线程是 CPU 调度的最小单位。

进程

在程序启动时,操作系统会给该程序分配一块内存空间,对于程序但看到的是一整块连续的内存空间,称为虚拟内存空间,落实到操作系统内核则是一块一块的内存碎片的东西。为的是节省内核空间,方便对内存管理。
就这片内存空间,又划分为用户空间与内核空间,用户空间只用于用户程序的执行,若要执行各种 IO 操作,就会通过系统调用等进入内核空间进行操作。每个进程都有自己的 PID。

线程

线程是进程的一个执行单元,一个进程可以包含多个线程,只有拥有了线程的进程才会被 CPU 执行,所以一个进程最少拥有一个主线程。
由于多个线程可以共享同一个进程的内存空间,线程的创建不需要额外的虚拟内存空间,线程之间的切换也就少了如进程切换的切换页表,切换虚拟地址空间此类的巨大开销。至于进程切换为什么较大,简单理解是因为进程切换要保存的现场太多如寄存器,栈,代码段,执行位置等,而线程切换只需要上下文切换,保存线程执行的上下文即可。线程的的切换只需要保存线程的执行现场(程序计数器等状态)保存在该线程的栈里,CPU 把栈指针,指令寄存器的值指向下一个线程。相比之下线程更加轻量级。
可以说进程面向的主要内容是内存分配管理,而线程主要面向的 CPU 调度。

协程

虽然线程比进程要轻量级,但是每个线程依然占有1M左右的空间,在高并发场景下非常吃机器内存,比如构建一个http服务器,如果一个每来一次请求分配一个线程,请求数暴增容易OOM,而且线程切换的开销也是不可忽视的。同时,线程的创建与销毁同样是比较大的系统开销,因为是由内核来做的,解决方法也有,可以通过线程池或协程来解决。
协程是用户态的线程,比线程更加的轻量级,操作系统对其没有感知,之所以没有感知是由于协程处于线程的用户栈能感知的范围,是由用户创建的而非操作系统。

如一个进程可拥有以有多个线程一样,一个线程也可以拥有多个协程。协程之于线程如同线程之于 CPU,拥有自己的协程队列,每个协程拥有自己的栈空间,在协程切换时候只需要保存协程的上下文,开销要比内核态的线程切换要小很多。