Last active
August 22, 2025 16:29
-
-
Save jordanorelli/4db89b94e505c39a78efbb19f0ad81fd to your computer and use it in GitHub Desktop.
asyncio timeouts are cursed
This file contains hidden or 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 | |
| import time | |
| import random | |
| from collections.abc import Callable | |
| def roll(dice: int = 1, sides: int = 6) -> int: | |
| total = 0 | |
| for _ in range(dice): | |
| total += random.randint(1, sides) | |
| return total | |
| async def call[**P, T](f: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: | |
| return f(*args, **kwargs) | |
| def run_sync(num_dice: int) -> float: | |
| start = time.monotonic() | |
| roll(num_dice) | |
| elapsed = time.monotonic() - start | |
| return elapsed | |
| async def main(): | |
| num_dice = 10_000_000 | |
| # Run the work sync to establish how long we expect the work to take, then | |
| # use half of that time as our timeout value. | |
| timeout = run_sync(num_dice) * 0.5 | |
| # Now run the work "async", but give it half of the amount of time that the | |
| # work takes to do. What does the timeout mechanism do? | |
| start = time.monotonic() | |
| try: | |
| coro = call(roll, num_dice) | |
| await asyncio.wait_for(coro, timeout) | |
| elapsed = time.monotonic() - start | |
| print( | |
| f"ASYNC Succeeded after an elapsed time of {elapsed} using a timeout of {timeout}" | |
| ) | |
| except asyncio.TimeoutError as e: | |
| elapsed = time.monotonic() - start | |
| print(f"Timed out after {elapsed} with error: {e}") | |
| asyncio.run(main()) |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
the output: