asyncio.gather(tasks1, task2, ...)
的作用:
- 并发执行多个协程 - 将多个协程封装, 这些协程会并发执行, 相当于同时异步启动多个任务.
- 等待多个协程完成 - 会等待所有的协程执行结束后才返回结果, 从而避免需要手动等待每个协程完成.
- 提取协程返回值 - 将各个协程的返回值合并到一个列表中返回, 便于获取执行结果。
举个例子:
import asyncio
async def func1():
print('func1 started')
await asyncio.sleep(2)
return 'result of func1'
async def func2():
print('func2 started')
await asyncio.sleep(3)
return 'result of func2'
async def main():
res = await asyncio.gather(func1(), func2())
print(res)
asyncio.run(main())
func1 started
func2 started
['result of func1', 'result of func2']
在这个例子里面, 我们定义的都是异步函数, 调用asynico.run
来使整个程序run
起来, 不然还需要我们手动的send(None)
来执行代码, asyncio.run()
内部会先创建一个事件循环,然后执行main()
协程, 在这里使用了很多的await
, 再次理解是 : await
相当于递归进去, 让你先去执行这个await
里面的东西, 等你执行完了再把值返回回来.
然后我们再理解下run
在干什么, 他会一直run
直到遇见StopIteration
, 伪代码如下:
while True:
try:
x = self.coro.send(None)
except StopIteration as e:
result = e.value
else:
func, arg = x
func(arg)
而后面的着一个部分func(arg)
正是完成最底层的那个任务的需求, 最底层可以使用一个awaitable
的一个对象, 然后使用: await Awaitable((function, args))
, 这个时候最底层函数释放执行权, 将执行权交给顶层函数, 顶层函数执行完了之后再send(None)
下来, 继续完成后续的操作, 如果有返回值的话就返回值, 和递归很像, 但是递归强调的是分解任务, 而协程强调的是协作, 可以等, 并且让出执行权.
然后接着代码, 这里是res
等于gather
最终的返回值, 所以要先等到gather
的运行结束, 然后gather
调用两个func
, 等到两个func
都执行结束, 返回值交给res
, 虽然一个需要
2
s
2s
2s一个需要
3
s
3s
3s但是gather
会等到所有都结束了再传给res
, 相当于省下了写join
, 非常的方便