结合 Promise.all 这样的可等待对象

Combine awaitables like Promise.all

在异步 JavaScript 中,使用 Promise.all:

很容易并行 运行 任务并等待所有任务完成
async function bar(i) {
  console.log('started', i);
  await delay(1000);
  console.log('finished', i);
}

async function foo() {
    await Promise.all([bar(1), bar(2)]);
}

// This works too:
async function my_all(promises) {
    for (let p of promises) await p;
}

async function foo() {
    await my_all([bar(1), bar(2), bar(3)]);
}

我试图在 python 中重写后者:

import asyncio

async def bar(i):
  print('started', i)
  await asyncio.sleep(1)
  print('finished', i)

async def aio_all(seq):
  for f in seq:
    await f

async def main():
  await aio_all([bar(i) for i in range(10)])

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

但它按顺序执行我的任务。

等待多个可等待对象的最简单方法是什么? 为什么我的方法不起作用?

等同于使用 asyncio.gather:

import asyncio

async def bar(i):
  print('started', i)
  await asyncio.sleep(1)
  print('finished', i)

async def main():
  await asyncio.gather(*[bar(i) for i in range(10)])

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

Why doesn't my approach work?

因为当您 await seq 中的每个项目时,您会阻止该协程。所以本质上,你有伪装成异步的同步代码。如果您确实想要,您可以使用loop.create_taskasyncio.ensure_future.

实现您自己的asyncio.gather版本

编辑

原来的回答用的是下级asyncio.wait

我注意到如果我们想要有序的结果,asyncio.gather() 可能是比 asyncio.wait() 更好的等待方式。

如文档所示,asyncio.gather() 方法的结果值顺序对应于 aws 中可等待对象的顺序。但是,asyncio.wait() 的结果值顺序不会相同 thing.You 可以测试它。

https://docs.python.org/3/library/asyncio-task.html#asyncio.gather

asyncio.gather() 将 return 每个异步函数调用的输出列表。

import asyncio

async def bar(i):
    print('started', i)
    await asyncio.sleep(1)
    print('finished', i)
    return i

async def main():
    values = await asyncio.gather(*[bar(i) for i in range(10)])
    print(values)

asyncio.run(main())

此方法 gather 为并发作业采用任意数量的参数而不是列表,因此我们解包。

需要这个中间值是很常见的,values 在我的例子中,而不是将你的 function/method 设计成有副作用。