进程、线程与协程:调度机制与演进
3 分钟阅读42 次浏览
进程、线程与协程:调度机制与演进
基本概念
- 进程:操作系统调度系统资源的基本单位。进程类似于资源场地,提供程序运行所需的“地盘”。
- 线程:CPU 调度的基本单位,是可执行的片段,即“干活的苦力”。
- 协程:运行在用户态,由用户层面控制线程的工作内容,完全不需要经过系统内核。
这三者的关系可以这样理解:进程提供“地盘”,线程是“干活的苦力”,内核是“发号施令的总管”。I/O 和网络操作可以看作是苦力(线程)指派总管(内核)去干的外包活;而 CPU 调度,就是总管决定把机床(CPU)分配给哪个苦力(线程)去使用。 协程则是在同一个苦力(线程)内部,瞬间变换多种操作手法(任务),省去了向总管汇报的麻烦。
线程切换 vs 协程切换
- 线程切换(内核调度):操作系统每隔几毫秒发出时钟中断,强行抢走当前线程的 CPU,保存它的上下文,再换上另一个线程。这个过程需要从用户态切换到内核态,再切回来,开销较大,且频率由内核控制(抢占式)。
- 协程切换(用户态调度):协程完全在用户态下切换。它根本不需要惊动操作系统内核,不需要“系统调用”,只是把当前函数里的寄存器状态保存一下,然后跳转到另一个函数去执行。这个过程就像工人自己把手里的 A 图纸放下,拿起 B 图纸接着干,完全不需要跟“调度中心”汇报。
Java 中的虚拟线程
核心机制:Continuation(续体)
虚拟线程之所以能实现“阻塞而不挂起”,靠的是 JVM 内部的 Continuation 机制。
当你在虚拟线程里发起一个阻塞的 IO 调用(比如 Socket.read())时:
- 挂起(Yield):JVM 会感知到阻塞,它会自动把当前虚拟线程的栈帧(Stack Frames)从堆外内存拷贝到 Java 堆(Heap)中,并释放底层的载体线程。
- 轮询与唤醒:底层的操作系统继续处理 IO。当数据返回后,JVM 收到通知,再把堆里的栈帧拷贝回载体线程,继续从上次断掉的地方往下跑。
这种设计让虚拟线程在遇到阻塞时不再像传统线程那样挂起操作系统线程,从而大幅提升了吞吐量。
Python 中的协程:asyncio
Python 的 asyncio 是典型的用户态协程实现,与前面描述的协程原理完全一致。它通过事件循环(event loop)在单线程内调度多个协程任务,遇到 IO 操作时主动让出控制权,不依赖内核切换,从而高效利用 CPU。
评论
加载评论中...