Combine awaitables like Promise.all
Solution 1
The equivalent would be using 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?
Because when you await
each item in seq
, you block that coroutine. So in essence, you have synchronous code masquerading as async. If you really wanted to, you could implement your own version of asyncio.gather
using loop.create_task
or asyncio.ensure_future
.
EDIT
The original answer used the lower-level asyncio.wait
.
Solution 2
I noticed that asyncio.gather() may be a better way to await other than asyncio.wait() if we want ordered results.
As the docs indicates, the order of result values from asyncio.gather() method corresponds to the order of awaitables in aws. However, the order of result values from asyncio.wait() won't do the same thing.You can test it.
Solution 3
https://docs.python.org/3/library/asyncio-task.html#asyncio.gather
asyncio.gather()
will return the list of output from each async function calls.
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())
This method, gather, takes arbitrary number of args for the concurrent jobs instead of a list, so we unpack.
It's very common to need this intermediate value, values
in my eg, instead of designing your function/method to have side effects.
Related videos on Youtube
Tamas Hegedus
I am an enthusiastic computer scientist. #SOreadytohelp
Updated on March 08, 2022Comments
-
Tamas Hegedus about 2 years
In asynchronous JavaScript, it is easy to run tasks in parallel and wait for all of them to complete using
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)]); }
I tried to rewrite the latter in 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()
But it executes my tasks sequentially.
What is the simplest way to await multiple awaitables? Why doesn't my approach work?
-
Andrew Svetlov over 8 yearsplease mention asyncio.gather too
-
Thomas Ahle about 6 yearsIs the main difference between
wait
andgather
thatwait
allows atimeout
argument? -
Rémi Benoit almost 3 yearsasyncio.wait is the more low level way of waiting. Also in 3.8 passing coroutines to wait directly is deprecated. Please rewrite your answer or update with a snippet using asyncio.gather as it's closer to Promise.all.
-
Jorge Tovar almost 2 yearsWhat's the difference if the function returns a value?