为何我的asyncio程序运行时长远超预期?预期8秒实际耗时14秒
问题分析与解决
你的程序实际耗时14秒,核心原因是**asyncio.gather会等待所有传入的协程任务全部完成才会结束**,而你传入的第一个任务sometask(f, 0, 2, 6, gen1)的总执行时长刚好是14秒,拖慢了整个程序的结束时间。
任务耗时拆解
我们分别计算两个任务的执行时间线:
第一个任务(gen1)
- 先执行
await asyncio.sleep(2),耗时2秒 - 进入
async for循环,处理第一个生成器值:- 写入数据后,执行
await asyncio.sleep(6),耗时6秒(累计2+6=8秒)
- 写入数据后,执行
- 处理第二个生成器值:
- 写入数据后,执行
await asyncio.sleep(6),耗时6秒(累计8+6=14秒)
这个任务总耗时14秒。
- 写入数据后,执行
第二个任务(gen2)
- 先执行
await asyncio.sleep(0),无耗时 - 进入
async for循环,处理第一个生成器值:- 写入数据后,执行
await asyncio.sleep(4),耗时4秒(累计4秒)
- 写入数据后,执行
- 处理第二个生成器值:
- 写入数据后,执行
await asyncio.sleep(4),耗时4秒(累计4+4=8秒)
这个任务总耗时8秒。
- 写入数据后,执行
因为asyncio.gather要等所有任务完成,所以程序总耗时由最长的任务决定,也就是14秒,和你的预期不符。
修正方案(如果想让总时长控制在8秒)
如果希望程序总耗时为8秒,需要调整第一个任务的sleep时长,让它的总耗时不超过8秒。比如把sleep2从6改成3:
import asyncio import time async def gen1(): yield b'1a1a' yield b'2b2b' async def gen2(): yield b'3c3c' yield b'4d4d' async def sometask(file, offset, sleep1, sleep2, gen): await asyncio.sleep(sleep1) async for blok in gen(): file.seek(offset) file.write(blok) offset = file.tell() await asyncio.sleep(sleep2) async def main(): with open('file', 'wb+') as f: await asyncio.gather( sometask(f, 0, 2, 3, gen1), # sleep2改为3 sometask(f, 8, 0, 4, gen2)) start = time.perf_counter() asyncio.run(main()) print(time.perf_counter()-start, 's')
此时第一个任务总耗时:2+3+3=8秒,和第二个任务耗时一致,程序总时长就会是8秒左右。
另外注意:多个协程同时操作同一个文件对象时,虽然这里用了seek指定偏移量避免覆盖,但实际场景中如果有更复杂的文件操作,建议考虑加锁(比如asyncio.Lock)避免并发写入的潜在问题。
内容的提问来源于stack exchange,提问作者Eclipse Kelby
相关产品推荐
相关产品推荐

