asyncio.gather和asyncio.wait的区别
环境: python3.7.1
参考: https://stackoverflow.com/questions/42231161/asyncio-gather-vs-asyncio-wait
wait执行顺序是随机的,gather执行顺序是有序的
import asyncio
import time
async def add(x=1, y=2):
print(f'Add {x} + {y}')
await asyncio.sleep(2)
return x+y
loop = asyncio.get_event_loop()
tasks = [add(x, y) for x, y in zip(range(1, 10), range(11, 20))]
wait执行的顺序每次都是不一样的
s = time.time()
loop.run_until_complete(asyncio.wait(tasks))
print(f'cost {time.time()-s}')
>>>
Add 4 + 14
Add 8 + 18
Add 5 + 15
Add 9 + 19
Add 7 + 17
Add 1 + 11
Add 2 + 12
Add 6 + 16
Add 3 + 13
cost 2.005099058151245
但gather执行但顺序是有序的
s = time.time()
loop.run_until_complete(asyncio.gather(*tasks))
print(f'cost {time.time()-s}')
loop.close()
>>>
Add 1 + 11
Add 2 + 12
Add 3 + 13
Add 4 + 14
Add 5 + 15
Add 6 + 16
Add 7 + 17
Add 8 + 18
Add 9 + 19
cost 2.0041399002075195
gather和wait都能添加一组future,但gather更支持任务分组,而wait支持更低级别的精细操作
- gather可以对任务进行分组
import asyncio
async def add(x=1, y=2):
print(f'Add {x} + {y}')
await asyncio.sleep(2)
return x+y
loop = asyncio.get_event_loop()
# gather的顺序是添加到gather时的顺序
group3 = asyncio.gather(*[add(x, y) for x, y in zip(range(7, 10), range(16, 19))])
group2 = asyncio.gather(*[add(x, y) for x, y in zip(range(4, 7), range(13, 16))])
group1 = asyncio.gather(*[add(x, y) for x, y in zip(range(1, 4), range(10, 13))])
# 可以单独取消一组任务
group2.cancel()
# 因为gather已经将future丢到loop中了,所以这里执行一次空future就把之前到future一起执行了
loop.run_until_complete(asyncio.gather())
>>>
Add 7 + 16
Add 8 + 17
Add 9 + 18
Add 1 + 10
Add 2 + 11
Add 3 + 12
- wait则可以在第一个任务完成或指定时间后停止等待操作
async def add2(x=1, y=2):
await asyncio.sleep(random.uniform(1, 5))
return x+y
tasks = [add2(x, y) for x, y in zip(range(1, 10), range(11, 20))]
# wait可以在完成第一个任务完成或超时后等待停止
finished, unfinished = loop.run_until_complete(asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED))
print('get first result:')
for task in finished:
print(task.result())
print(f'unfinished:{len(unfinished)}')
print('get more result in 2 seconds:')
finished2, unfinished2 = loop.run_until_complete(
asyncio.wait(unfinished, timeout=2))
for task in finished2:
print(task.result())
print(f"unfinished2:{len(unfinished2)}")
print("Get all other results:")
finished3, unfinished3 = loop.run_until_complete(asyncio.wait(unfinished2))
for task in finished3:
print(task.result())