The documentation for asyncio.gather says that
If return_exceptions is
False
(default), the first raised exception is immediately propagated to the task that awaits ongather()
. Other awaitables in the aws sequence won’t be cancelled and will continue to run.
However, from a simple test it seems that if one of the tasks raises an exception when return_exceptions is False
, all other awaitable are cancelled (or to be more precise, in case the terminology is not clear to me, the other awaitables do not finish their job):
import asyncio async def factorial(name, number, raise_exception=False): # If raise_exception is True, will raise an exception when # the loop counter > 3 f = 1 for i in range(2, number + 1): print(f' Task {name}: Compute factorial({i})...') if raise_exception and i > 3: print(f' Task {name}: raising Exception') raise Exception(f'Bad Task {name}') await asyncio.sleep(1) f *= i print(f'==>> Task {name} DONE: factorial({number}) = {f}') return f async def main(): tasks = [factorial('A', 5), # this will not be finished factorial('B', 10, raise_exception=True), factorial('C', 2)] try: results = await asyncio.gather(*tasks) print('Results:', results) except Exception as e: print('Got an exception:', e) asyncio.run(main())
What this piece of code is doing, just to make it simpler, it defines 3 tasks and call asyncio.gather()
on them. One of the tasks raises an exception before one of the others is done, and this other task is not finished.
Actually, I cannot even make sense with what the documentations says - if an exception is raised and caught by the task awaiting on gather
, I would not even be able to get the returned results (even if the other task would, somehow, get done).
Am I missing anything, or is there a problem with the documentation?
This was tested with Python 3.7.2.
Specifically, code that runs in the asyncio event loop must not block - all blocking calls must be replaced with non-blocking versions that yield control to the event loop.
2 weeks ago. by Kalsoom Bibi. Asynchronous input/output or asyncio is a programming methodology that uses an event loop or a single thread to accomplish high concurrency. Python is not the only language or framework that uses the approach; JavaScript's NodeJS is maybe the most well-known.
Retrieving exceptions for each taskexception() : Returns the exception object raised by the coroutine, None if no exception as raised. result() : Returns the result of the coroutine, re-throws the exception if the coroutine raised an exception.
I've run your code and got the following output, as expected from documentation.
Task C: Compute factorial(2)... Task A: Compute factorial(2)... Task B: Compute factorial(2)... ==>> Task C DONE: factorial(2) = 2 Task A: Compute factorial(3)... Task B: Compute factorial(3)... Task A: Compute factorial(4)... Task B: Compute factorial(4)... Task B: raising Exception Got an exception: Bad Task B Task A: Compute factorial(5)... ==>> Task A DONE: factorial(5) = 120
await asyncio.gater()
returns immediately and print('Got an exception:', e)
to the screen.As @deceze commented, your program exited immediately after the exception was caught and main()
returns. Thus, the tasks A and C are terminated because the entire process dies, not because of cancellation.
To fix it, add await asyncio.sleep(20)
to the end of the main()
function.
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