I'd like to reproduce javascript's Promise.race behavior in Python code. I want to run group of coroutines simultaneously and return when first one is done, get its result and cancel/discard results of the ones that are still running.
You can use asyncio.wait with the argument return_when
set to FIRST_COMPLETED
. The example code below will print 1
and the exception will never be raised. The second for loop makes sure all of our pending coroutines are properly finished. If raising_wait
coroutine finishes first, after calling the result
method of the created Task object, the exception will be raised as specified in documentation. Last thing to mention is that, that using asyncio.wait
with FIRST_COMPLETED
doesn't guarantee that we will have exactly one Task in done set if the couroutines finish in almost same time.
from contextlib import suppress
import asyncio
async def wait(t):
await asyncio.sleep(t)
return t
async def raising_wait(t):
await asyncio.sleep(t)
raise TimeoutError("You waited for too long, pal")
loop = asyncio.new_event_loop()
task_set = set()
task_set.add(loop.create_task(wait(1)))
task_set.add(loop.create_task(raising_wait(2)))
task_set.add(loop.create_task(wait(3)))
done_first, pending = loop.run_until_complete(
asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED)
)
for coro in done_first:
try:
print(coro.result())
except TimeoutError:
print("cleanup after error before exit")
for p in pending:
p.cancel()
with suppress(asyncio.CancelledError):
loop.run_until_complete(p)
loop.close()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With