Created
September 20, 2022 15:03
-
-
Save tfarago/389d4960cf405cdd0ea166471f760f03 to your computer and use it in GitHub Desktop.
asyncio coroutines not running through
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio | |
RUNNING = set([]) | |
async def coro(name, howlong=5, raise_exc=None): | |
print('start', name) | |
if raise_exc: | |
raise raise_exc | |
try: | |
RUNNING.add(name) | |
await asyncio.sleep(howlong) | |
print('slept', name, howlong) | |
RUNNING.remove(name) | |
except BaseException as e: | |
print(f'except {e.__class__.__name__} start', name) | |
await asyncio.sleep(0.2) | |
if name in RUNNING: | |
RUNNING.remove(name) | |
print(f'except {e.__class__.__name__} finished', name) | |
raise | |
return name | |
async def gather_or_wait(use_gather=True, raise_exc=None): | |
loop = asyncio.get_running_loop() | |
try: | |
tasks = [ | |
loop.create_task(coro(1, howlong=1)), | |
loop.create_task(coro(2, howlong=2)), | |
loop.create_task(coro(3, howlong=3, raise_exc=raise_exc)), | |
] | |
if use_gather: | |
task = asyncio.gather(*tasks, return_exceptions=False) | |
await task | |
else: | |
await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED) | |
except BaseException as e: | |
print(f'{e.__class__.__name__} in gather_or_wait') | |
for task in tasks: | |
task.cancel() | |
# Actually it doesn't matter if we use gather or wait here. With Approach 1 we still | |
# don't run through and with Approach 3 we do. | |
if use_gather: | |
await asyncio.gather(*tasks, return_exceptions=True) | |
else: | |
await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED) | |
def main(): | |
global RUNNING | |
# Approach 1: doesn't work | |
try: | |
asyncio.run(gather_or_wait(use_gather=True, raise_exc=KeyboardInterrupt)) | |
except KeyboardInterrupt: | |
print('KeyboardInterrupt in main') | |
print('run gather: unfinished:', RUNNING) | |
RUNNING = set([]) | |
print('\n------------------------------\n') | |
# Approach 2: doesn't work | |
loop = asyncio.new_event_loop() | |
asyncio.set_event_loop(loop) | |
task = loop.create_task(gather_or_wait(use_gather=True, raise_exc=KeyboardInterrupt)) | |
try: | |
loop.run_until_complete(task) | |
except KeyboardInterrupt: | |
print('KeyboardInterrupt in main') | |
task.cancel() | |
loop.run_until_complete(task) | |
loop.stop() | |
loop.close() | |
print('manual gather: unfinished:', RUNNING) | |
RUNNING = set([]) | |
print('\n------------------------------\n') | |
# Approach 3: works | |
loop = asyncio.new_event_loop() | |
asyncio.set_event_loop(loop) | |
task = loop.create_task(gather_or_wait(use_gather=False, raise_exc=KeyboardInterrupt)) | |
try: | |
loop.run_until_complete(task) | |
except KeyboardInterrupt: | |
print('KeyboardInterrupt in main') | |
task.cancel() | |
loop.run_until_complete(task) | |
loop.stop() | |
loop.close() | |
print('manual wait: unfinished:', RUNNING) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment