你列的这 6 个其实是不同层次的东西,还混进了「机制」和「实体」。本页先用一张主图理顺层次,再逐个拆解 + 对比。
它不是一种「实体」,而是操作系统调度内核线程的手段:每个可运行线程分到一个时间片(quantum),用完(或被更高优先级抢占)就切到下一个。单核上这是「并发假象」,多核上是「并行 + 分片」叠加。
但分片本身不增加算力——它只是把已有的 CPU 时间切开分配。要真正同时干多件事,得靠多核 / 超线程(下一节)。
这是纯硬件特性。一个物理核心内部,复制出两套独立的「架构状态」(寄存器、程序计数器等),但共享执行单元、缓存、流水线。于是 OS 看到的是 2 个「逻辑 CPU」,可同时塞两个线程进去。
两者常被一起提,但角色不同:
所以一台 8 核 16 线程(每核 2 超线程) 的机器,OS 看到 16 个逻辑 CPU,每个再用时间分片调度一堆内核线程——这就是你看到的「能跑远超 16 个进程却很流畅」的底层原因。
进程是操作系统分配资源的基本单位:它拥有独立的虚拟地址空间(自己的页表/mm_struct)、文件描述符表、信号处理等。一个进程里至少包含 1 个内核线程(主线程),多线程进程则包含多个。
这就是你清单里单独的「操作系统级别线程」,也是 pthread_create 造出来的东西。它的正式名字是内核线程 / 轻量级进程(LWP)——操作系统真正调度上 CPU 的单位。
| 维度 | 进程 | 内核线程(OS线程) |
|---|---|---|
| 地址空间 | 独立(自己一套页表) | 共享所属进程的页表 |
| 角色 | 资源容器 | 执行流 / 调度单位 |
| 创建开销 | 重(建页表、拷贝资源) | 较轻(共享地址空间) |
| 切换 | 换页表(TLB 刷) | 同进程内不换页表 |
这就是广义「线程」里不属于 OS 的那一半。goroutine、Java 虚拟线程、Erlang 进程、老版 Java 绿线程都是它。它们完全存在于用户态,OS 看不见,由语言运行时用调度器把成千上万个用户线程多路复用到少量内核线程上(M:N 模型)。
协程是用户线程里「协作式」的那一档:它不会被迫让出 CPU,必须自己主动 yield(或 await)才把控制权交还调度器。Python asyncio、Lua、Kotlin 协程、C++20 协程都是典型。
一句话:协程 ⊂ 用户线程。它们都是「用户态、不进内核切换」这一大类,区别在「让不让 OS/运行时强行抢」。而用户线程 ⊃ 协程,又隔着一层 M:N 才到 OS 线程。
| 维度 | 协程 | 用户线程(绿线程) | OS线程(内核线程) | 进程 | 超线程 | 时间分片 |
|---|---|---|---|---|---|---|
| 所在层 | 运行时 | 运行时 | 操作系统 | 操作系统 | 硬件 | 机制(OS) |
| 管理者 | 运行时/事件循环 | 语言运行时 | OS 调度器 | OS | CPU 硬件 | OS 定时器 |
| 调度方式 | 协作式 | 多协作/抢占 | 抢占式 | 抢占式 | 硬件并行 | 时间轮转 |
| 切换是否进内核 | 否 | 否 | 是 | 是 | — | 是(切线程时) |
| 切换开销 | 极小(寄存器) | 很小 | 中(进内核+可能换页表) | 大(换页表) | — | — |
| 是否共享地址空间 | 同线程内 | 同进程内 | 同进程内 | 独立 | 核内共享 | — |
| 并行能力 | 单线程 | 靠底层多线程 | 跨核真并行 | 跨核真并行 | 核内并行 | 假象/叠加 |
| 典型代表 | asyncio/Lua/Kotlin | goroutine/虚拟线程 | pthread | fork 出的程序 | Intel HT | OS 调度 |