Комбинируйте awaitables как 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()
Но он выполняет мои задачи последовательно.
Каков самый простой способ подождать нескольких ожидающих?
Почему мой подход не работает?
Ответы
Ответ 1
Эквивалент будет использовать asyncio.wait
:
import asyncio
async def bar(i):
print('started', i)
await asyncio.sleep(1)
print('finished', i)
async def main():
await asyncio.wait([bar(i) for i in range(10)])
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Почему мой подход не работает?
Потому что, когда вы await
каждый элемент в seq
, вы блокируете эту сопрограмму. Таким образом, по сути, у вас есть синхронный код, маскирующий как асинхронный. Если вы действительно этого хотели, вы могли бы реализовать свою собственную версию asyncio.wait
с помощью loop.create_task
или asyncio.ensure_future
.
ИЗМЕНИТЬ
Как упоминал Андрей, вы также можете использовать asyncio.gather
.
Ответ 2
Я заметил, что asyncio.gather() может быть лучшим способом ожидания, чем asyncio.wait(), если мы хотим упорядоченные результаты.
Как показывают документы, порядок значений результата из метода asyncio.gather() соответствует порядку ожидаемых значений в aws. Однако порядок значений результата из asyncio.wait() не будет делать то же самое. Вы можете проверить это.