Python asyncio force timeout

python, python-asyncio

Solution

No, you can't interrupt a coroutine unless it yields control back to the event loop, which means it needs to be inside a `yield from` call. `asyncio` is single-threaded, so when you're blocking on the `time.sleep(10)` call in your second example, there's no way for the event loop to run. That means when the timeout you set using `wait_for` expires, the event loop won't be able to take action on it. The event loop doesn't get an opportunity to run again until `coro` exits, at which point its too late.

This is why in general, you should always avoid any blocking calls that aren't asynchronous; any time a call blocks without yielding to the event loop, nothing else in your program can execute, which is probably not what you want. If you really need to do a long, blocking operation, you should try to use `BaseEventLoop.run_in_executor` to run it in a thread or process pool, which will avoid blocking the event loop:

import asyncio
import time
from concurrent.futures import ProcessPoolExecutor

@asyncio.coroutine
def coro(loop):
    ex = ProcessPoolExecutor(2)
    yield from loop.run_in_executor(ex, time.sleep, 10)  # This can be interrupted.

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait_for(coro(loop), 1))

Problem

Using asyncio a coroutine can be executed with a timeout so it gets cancelled after the timeout: ``` @asyncio.coroutine def coro(): yield from asyncio.sleep(10) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait_for(coro(), 5)) ``` The above example works as expected (it times out after 5 seconds). However, when the coroutine doesn't use `asyncio.sleep()` (or other asyncio coroutines) it doesn't seem to time out. Example: ``` @asyncio.coroutine def coro(): import time time.sleep(10) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait_for(coro(), 1)) ``` This takes more than 10 seconds to run because the `time.sleep(10)` isn't cancelled. Is it possible to enforce the cancellation of the coroutine in such a case? If asyncio should be used to solve this, how could I do that?

Original source