Hi,

I've been experimenting with asyncio in Python 3.4.2 and run into some 
interesting behaviour when attempting to use ayncio.wait_for with a 
Condition:

import asyncio

loop = asyncio.get_event_loop()
cond = asyncio.Condition()

@asyncio.coroutine
def foo():
    #with (yield from cond):
    yield from cond.acquire()
    try:
        try:
            # Wait for condition with timeout
            yield from asyncio.wait_for(cond.wait(), 1)
        except asyncio.TimeoutError:
            print("Timeout")
    finally:
        # XXX: Raises RuntimeError: Lock is not acquired.
        cond.release()

loop.run_until_complete(foo())


Taking a look around with a debugger I can see that the cond.wait() 
coroutine task receives a CancelledError as expected and this attempts to 
reacquire the lock associated with the condition (yield from 
self.acquire()). Unfortunately because asyncio.wait_for(...) immediately 
raises a TimeoutError, it's too late and we've already called called 
cond.release() in our main task, causing a runtime error.

My current workaround is to roll my own condition timeout-cancellation 
logic, but it really seems like wait_for and Condition should be able to 
play nicer together.

@asyncio.coroutine
def cond_wait_timeout(condition, timeout):
    wait_task = asyncio.async(condition.wait())
    loop.call_later(timeout, wait_task.cancel)
    try:
        yield from wait_task
        return True
    except asyncio.CancelledError:
        return False


Any thoughts?

Reply via email to