asyncio.create_task实际工作机制解析:基于示例代码的技术疑问
理解asyncio.create_task的工作机制
第一段代码(耗时约2秒)
import asyncio import time async def delayer(): await asyncio.sleep(1) async def messenger(): await asyncio.sleep(1) return "A Message" async def main(): message = await messenger() await delayer() start_time = time.time() asyncio.run(main()) end_time = time.time() - start_time print(end_time)
这段代码里,await messenger()会阻塞当前main协程,必须等messenger内部的asyncio.sleep(1)执行完、拿到返回值后,才会继续执行await delayer()。两个1秒的等待是串行执行的,所以总耗时约2秒。
第二段代码(耗时约1秒)
import asyncio import time async def delayer(): await asyncio.sleep(1) async def messenger(): await asyncio.sleep(1) return "A Message" async def main(): task1 = asyncio.create_task(delayer()) task2 = asyncio.create_task(delayer()) await task1 await task2 start_time = time.time() asyncio.run(main()) end_time = time.time() - start_time print(end_time)
这段代码总耗时仅约1秒,核心差异就在asyncio.create_task的使用逻辑上。
核心疑问解答
你疑惑的“既然await需要等待返回,用了create_task为什么不会总耗时2秒”,可以拆解成两个关键逻辑:
- create_task的即时调度特性:调用
asyncio.create_task(delayer())时,会立刻把delayer协程包装成任务对象,提交给asyncio事件循环,事件循环会尽快启动这个任务的执行——也就是说,task1和task2对应的delayer代码,在你调用create_task之后就已经开始运行了,不是等你await的时候才启动。 - await对任务对象的非独占阻塞:当你
await task1时,确实会暂停当前的main协程,但事件循环不会闲着,它会立刻去调度其他已经就绪的任务(比如task2)。在这个示例里,两个delayer内部的asyncio.sleep(1)是同时开始计时的,1秒后两个sleep都完成,后续的await task1和await task2都会快速结束,所以总耗时约1秒。
结合你已掌握的知识点补充:
- await是“协程内阻塞”而非“进程阻塞”:await只会暂停当前所在的协程,整个进程不会卡住,事件循环会去处理其他可运行的任务/协程。
- create_task的本质是“并行预约”:它把协程变成可被事件循环调度的独立任务,相当于提前给协程排了号,让事件循环能在当前协程暂停时,去执行这些预约好的任务。
对比第一段代码就能更清楚:第一段里只有messenger一个协程在等待,事件循环无事可做只能等它完成;而第二段通过create_task提前提交了两个任务,当第一个await暂停main时,事件循环可以去跑第二个任务,让两个sleep并行执行。
内容的提问来源于stack exchange,提问作者Terra Green
相关产品推荐
相关产品推荐

