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?