最近在学习ASGI(Asynchronous Server Gateway Interface)的时候,看到一句话:
“ASGI的并发 ≈ 一个event loop 同时挂起的协程数”
所以,进程,线程,协程到底是什么关系?事件循环又是什么东西?
一、进程、线程、协程的区别
- 进程(process)
- 定义:操作系统分配资源(CPU时间、内存空间等)的最小单位。
- 特点:
- 每个进程都有自己独立的内存空间。
- 进程之间相互独立,通信要靠管道、消息队列、共享内存
- 开销大,切换成本高
- 类比:一台太独立的电脑,各自运行一套系统
- 现成(Thread)
- 定义:CPU调度的最小单位,一个进程里面可以有多个线程
- 特点
- 共享同一个进程内的内存资源
- 切换成本比进程小
- 容易出现数据竞争,需要枷锁
- 类比:同一台电脑里的多个应用窗口,公用内存和硬盘,但干活各自分开
- 协程(coroutine)
- 定义:用户态的“轻量级线程”,有程序自己调度。
- 特点
- 通过async/await 来挂起和恢复执行。
- 单线程内实现高并发。
- 成本绩效,可以轻松支撑成千上万任务
- 缺点:本身不能利用多核(需要结合多进程)
- 类比:浏览器里面一个窗口的多个标签页,虽然只有一个窗口线程,但是你能快速切换任务,感觉像是并发的。
4.三者对比
| 特性 | 进程 | 线程 | 协程 |
|---|---|---|---|
| 调度者 | 操作系统 | 操作系统 | 程序自身(时间循环) |
| 内存空间 | 独立 | 共享进程内存 | 共享线程内存 |
| 切换开销 | 大 | 中 | 极小 |
| 并发数量 | 少(几十~上百) | 中(中~几千) | 多(几万+) |
| 多核利用 | √ | √ | ×(需多进程) |
二、层级关系梳理
很多人会误解成:进程⊃线程⊃协程
其实更精准的表述是:进程 ├── 线程1 │ └── (事件循环1) │ ├── 协程a │ ├── 协程b │ └── 协程c ├── 线程2 │ └── (事件循环2) │ ├── 协程d │ └── 协程e └── 线程3 └── (可能没有事件循环,只跑普通任务)在Python的ASGI框架(如FastApi+uvicorn)里,最常见的模式就是:一个进程,一个线程,一个事件循环,上万协程
三、什么是时间循环
- 定义
时间循环(event loop)就是一个调度器
他会不断循环,检查哪些协程准备好执行,然后把CPU时间分配给他们。
协程在await I/O时,会主动把执行权交还给时间循环;I/O完成后,loop会把任务切回来继续执行。
- 类比
传统服务员:
传统阻塞:服务员全城只能盯着一个客人
事件循环:点完单就去服务下一个客人,等厨房喊菜在回来继续。
一个人看似能同时服务很多客人
- 示例
async def task(name, sec):
print(f"{name} 开始")
await asyncio.sleep(sec)
print(f"{name} 结束")
async def main():
await asyncio.gather(
task("任务1", 1),
task("任务2", 2),
task("任务3", 3),
task("任务4", 4),
)
asyncio.run(main())
#输出结果
任务1 开始
任务2 开始
任务3 开始
任务4 开始
任务1 结束
任务2 结束
任务3 结束
任务4 结束
四、怎么启动
- 启动一个线程
import threading
def worker():
print("启动了一个线程")
t = threading.Thread(target=worker)
t.start()
t.join()
- 启动一个进程
from multiprocessing import Process
def worker():
print("启动了一个进程")
if __name__ == "__main__":
p = Process(target=worker)
p.start()
p.join()
- 启动一个事件循环(在线程里)
import threading, asyncio
async def coro():
await asyncio.sleep(1)
print("协程完成")
def loop_thread():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_forever()
t = threading.Thread(target=loop_thread)
t.start()
- 启动一个协程
import asyncio
async def task():
await asyncio.sleep(1)
return "ok"
async def main():
result = await task()
print(result)
asyncio.run(main())
五、总结
进程:操作系统资源单位,重量级
线程:CPU调度单位,共享进程内存
协程:轻量级任务,由事件循环调度
事件循环:线程里的调度器,管理协程的挂起和恢复
在Python的async/await的世界里面:
- 协程是主角,事件循环是导演,线程是舞台,进程是一整栋剧院
而ASGI的高并发,本质就是:一个事件循环里同时挂起成千上万个协程
2万+

被折叠的 条评论
为什么被折叠?



