进程是什么,协程是什么

我们可以把计算机比作一个大工厂,从资源管理执行效率两个维度来拆解。

先上核心结论:进程是“资源分配”的最小单位,线程是“CPU调度”的最小单位,而协程是“用户态”的轻量级执行单元。


1. 进程(Process):工厂里的“独立车间”

  • 是什么:进程是操作系统进行资源分配(内存、文件句柄、网络端口)的基本单位。它是正在运行的程序的一个实例。

  • 工厂类比:相当于一个独立的车间。每个车间都拥有自己完整的地盘(独立的内存空间)、物料(数据)和机器(资源)。

  • 核心特点(隔离性)

    • 独立性:进程间的内存是相互隔离的。车间 A 无法直接访问车间 B 的内存,如果 A 崩溃了,完全不影响 B(所以多进程安全性最高)。

    • 重量级:创建和销毁一个进程,需要操作系统分配大量的系统资源(页表、PCB控制块等),开销很大。

    • 切换成本高:CPU 从一个进程切换到另一个进程,需要保存当前全部运行状态,还要刷新缓存(TLB),速度较慢。

2. 协程(Coroutine / Goroutine):车间里的“流水线工人”

  • 是什么:协程是比线程更轻量级的用户态执行单元。它完全由编程语言运行时(如 Go 的调度器)进行管理和调度,而不是由操作系统内核管理。

  • 工厂类比:相当于车间里一个个灵活的兼职工人(针对 Go 的 Goroutine,则是“超轻量虚拟工人”)。他们没有固定的工位(栈空间极小,Go 中初始仅 2KB),可以随时被组长安排到某个机器上干活,干完立刻让出位置。

  • 核心特点(轻量且高效)

    • 用户态调度:创建、销毁、切换都在用户态完成,不陷入内核态,不涉及系统调用,速度极快(纳秒级)。

    • 栈空间动态伸缩:内存占用极小,且能自动扩容,一台普通的 16GB 服务器轻松创建几十万甚至上百万个(有别于我们之前纠正的“10万”误区)。

    • 非抢占式/协作式(通常):大多数协程需要主动让出执行权(Go 的 Goroutine 在阻塞 I/O 或调用runtime.Gosched时会自动让出)。


关键区分:进程、线程、协程的终极对比

为了帮你彻底理清,这里加上线程(Thread)来做对比(线程是进程内的执行者,属于内核级调度):

维度进程线程协程
管理方操作系统内核操作系统内核用户态(语言运行时,如 Go runtime)
资源隔离性完全隔离(独立内存空间)共享进程的内存空间(堆、全局变量)完全共享所属线程/进程的内存空间
上下文切换成本极高(涉及虚拟内存切换、TLB刷新)较高(内核态切换,需保存寄存器)极低(仅保存少量寄存器,用户态切换)
内存占用很大(通常 GB 级虚拟内存)中等(MB 级默认栈空间)极小(Go 初始仅 2KB,可动态扩容)
创建/销毁成本极重(需 fork 系统调用)较重(需 pthread_create 系统调用)极轻(纯内存分配,无系统调用)
崩溃影响互不影响(隔离)导致整个进程崩溃(共享内存)导致所在线程/进程崩溃
并发模型仅用于多核并行(重量级)内核级抢占式调度用户态协作式/多对多调度(GMP 模型)

在 Go 语言的 GMP 模型中,三者的关系是:

  • 进程是操作系统分配的大房子(内存空间)。

  • 线程(M)是房子里正在干活的正式工人(操作系统线程),由内核派发工资(CPU 时间片)。

  • Goroutine(协程)是工人手里不断处理的具体任务单。Go 调度器(P)负责决定让哪个任务单交给哪个工人去执行。

一句话总结:进程管“地”(资源),线程管“人”(内核执行),协程管“活”(用户态任务)。Go 的高并发就是用极其廉价的协程任务,巧妙地挂载在少量昂贵的线程工人身上,从而榨干 CPU 性能。