Home > Back-end >  How to timeout asyncio.to_thread?
How to timeout asyncio.to_thread?

Time:02-21

I experimenting with the new asyncio features in Python 3.9, and have the following code:

import asyncio

async def inc(start):
    i = start
    while True:
        print(i)
        i  = 2
    return None

async def main():
    x = asyncio.gather(
        asyncio.to_thread(inc, 0),
        asyncio.to_thread(inc, 1)
    )
    try:
        await asyncio.wait_for(x, timeout=5.0)
    except asyncio.TimeoutError:
        print("timeout!")

asyncio.run(main())

My expectation is that the program will print numbers starting from 0 and terminate after 5 seconds. However, when I execute the program here, I see no output and the following warning:

/usr/lib/python3.9/asyncio/events.py:80: RuntimeWarning: coroutine 'inc' was never awaited
  self._context.run(self._callback, *self._args)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/usr/lib/python3.9/concurrent/futures/thread.py:85: RuntimeWarning: coroutine 'inc' was never awaited
  del work_item
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

CodePudding user response:

The asyncio.to_thread converts a regular function to a coroutine.

All you need is to change the async def inc to def inc. You can do this, because there is no await, it is not a real coroutine.

However, you cannot kill a thread. The timeout will cause to stop waiting, not to stop computing numbers.

UPDATE: In detail, the asyncio.gather awaits the coroutines until the timeout. When cancelled by the timeout, the gather cancels all still running coroutines a and waits for their termination. Cancelling a coroutine means to deliver an exception at the nearest await statement. In this case, there is no await and the coroutines will never receive the cancellation exception. The program hangs at that point.

  • Related