importasyncio
asyncdefmy_task(name,delay):print(f"Task{name}:starting")
awaitasyncio.sleep(delay)
print(f"Task{name}:finished")
asyncdefmain():print("Main:creatingtasks")
task1=asyncio.create_task(my_task("A",1))
task2=asyncio.create_task(my_task("B",0.5))
print("Main:taskscreated")
awaittask1
awaittask2
print("Main:finished")
asyncio.run(main())回答
– await task1 时把控制权交回事件循环,两个任务开始运行,按创建顺序通常先打印 Task A: starting,再 Task B: starting。
– B 休眠 0.5s,A 休眠 1s,故先结束 B,再结束 A。
– task1 结束后继续 await task2(已结束),最后 Main: finished。
事件循环是一个无限循环,它等待并分发事件,协调所有异步操作的执行顺序。
想象一个餐厅经理(事件循环):
顾客(协程)点餐后不会一直站在厨房门口等待
顾客回到座位(挂起),经理记录订单(注册事件)
厨房做好菜(I/O 完成),经理通知对应顾客(恢复协程)
经理在等待期间可以服务其他顾客(并发处理)
没有空闲时间,所有资源都被高效利用
asyncio 事件循环本身运行在单线程中,但 asyncio 可以与多线程协同工作,形成混合架构
事件循环 = 单线程引擎
所有协程在同一个线程中执行
通过 await 点实现协作式多任务
任何时候只有一个协程”活跃”(占用CPU)
没有线程切换开销,没有锁竞争,没有竞态条件
事件循环始终运行在 MainThread
上面代码:代码中main线程有3个协程:main、task1(A)和task2(B)
main协程只在这一行真正让出控制权:await task1 ,此时main协程处于waiting状态,这行代码的字面意思是:”等待 task1 完成”
asyncio.create_task()只是将协程注册到事件循环,不会立即执行。当前协程(main)会继续执行直到遇到await
asyncio是协作式多任务,不是抢占式调度
main WAITING_FOR_TASK1 等待队列 在 await task1 处暂停
task1 READY 就绪队列 被 create_task 创建,可执行
task2 READY 就绪队列 被 create_task 创建,可执行
事件循环只会从就绪队列中选择协程执行,而 main 此时在等待队列中
await asyncio.sleep(1) 时:
✅ 不是阻塞:只是注册一个 1 秒后的定时器
✅ 主动让出:协程明确告诉事件循环”我现在不能继续”
✅ 精准调度:事件循环检查就绪队列,发现 task2 可以运行
✅ 零 CPU 浪费:在等待期间,线程完全休眠
✅ 确定性恢复:1 秒后精确恢复 task1,从 await 之后继续
这是协程,不是线程
- 完全单线程:asyncio是基于单线程的协程模型,不是多线程
- 协作式多任务:协程通过主动让出控制权(通过
await)来实现并发,不像线程那样依赖操作系统的时间片调度 - 没有CPU时间切片:asyncio的调度不是基于CPU时间片,而是基于I/O事件完成和显式的让出控制权
2. 事件循环和执行流程
- 确定性的执行顺序:asyncio的执行顺序是确定的,不是随机的
- main函数也是一个协程:它和其他任务一样由事件循环调度
- await的真正含义:
await task1不是将main加入等待队列,而是”挂起当前协程,直到task1完成,同时允许其他任务运行”
-
CPU 密集型 vs I/O 密集型:
- CPU 密集型任务:确实需要独占 CPU
- I/O 密集型任务:99% 时间在等待 I/O,不占用 CPU
- asyncio 专为 I/O 密集型场景优化
版权:言论仅代表个人观点,不代表官方立场。转载请注明出处:https://www.stntk.com/question/190.html
还没有评论呢,快来抢沙发~