[Python-Dev] asyncio: how to interrupt an async def w/ finally: ( e.g. Condition.wait() )
The following code has a problem: the generator returned by .wait() has a finally: section. When self.stopped is set, it still needs to run. As it is asynchronous (it needs to re-acquire the lock), I need to come up with a reliable way to wait for it. If I don't, .release() will throw an exception because the lock is still unlocked. The best method to do this that I've come up with is the five marked lines. I keep thinking there must be a better way to do this (taking into account that I have no idea whether the 'await r' part of this is even necessary). ``` class StopMe(BaseException): pass class Foo: async dev some_method(self): self.uptodate = asyncio.Condition() self.stopped = asyncio.Future() … await self.uptodate.acquire() try: while self.some_condition(): w = self.uptodate.wait() await asyncio.wait([w,self.stopped], loop=self.conn._loop, return_when=asyncio.FIRST_COMPLETED) with contextlib.suppress(StopMe): # FIXME? r = w.throw(StopMe()) # FIXME? if r is not None: # FIXME? await r# FIXME? await w# FIXME? finally: self.uptodate.release() ``` ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] asyncio: how to interrupt an async def w/ finally: ( e.g. Condition.wait() )
On 19.12.2015 20:25, Guido van Rossum wrote: > Perhaps you can add a check for a simple boolean 'stop' flag to your > condition check, and when you want to stop the loop you set that flag > and then call notify() on the condition. Then you can follow the > standard condition variable protocol instead of all this nonsense. :-) Your example does not work. >def stop_it(self): >self.stopped = True >self.uptodate.notify() self.uptodate needs to be locked before I can call .notify() on it. Creating a new task just for that seems like overkill, and I'd have to add a generation counter to prevent a race condition. Doable, but ugly. However, this doesn't fix the generic problem; Condition.wait() was just what bit me today. When a non-async generator goes out of scope, its finally: blocks will execute. An async procedure call whose refcount reaches zero without completing simply goes away; finally: blocks are *not* called and there is *no* warning. I consider that to be a bug. -- -- Matthias Urlichs ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] asyncio: how to interrupt an async def w/ finally: ( e.g. Condition.wait() )
On 20.12.2015 01:26, Kevin Conway wrote: > async def coroutine(): > try: > await Awaitable() > await Awaitable() > finally: > print('finally') Try adding another "await Awaitable()" after the "finally:". I have to take back my "doesn't print an error" comment, however; there's another reference to the Condition.wait() generator (the task asyncio.wait() creates to wrap the generator in), and the "Task was destroyed but it is pending!" message got delayed sufficiently that I missed it. (Dying test cases tend to spew many of these.) Testcase: import asyncio import gc cond = asyncio.Condition() loop = asyncio.get_event_loop() async def main(): async with cond: # asyncio.wait() does this, if we don't w = asyncio.ensure_future(cond.wait()) await asyncio.wait([w],timeout=1) print(gc.get_referrers(w)) loop.run_until_complete(main()) Time to refactor my code to do the wait/timeout outside the "async with cond". -- -- Matthias Urlichs ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] iscoroutinefunction vs. coroutines
Hi, Is this pattern def foo(): return bar() async def bar(): await async def async_main(): await foo() considered to be valid? The reason I'm asking is that some code out there likes to accept a might-be-a-coroutine-function argument, using def run_callback(fn): if iscoroutinefunction(fn): res = await fn() else: res = fn() instead of def run_callback(fn): res = fn() if iscoroutine(res): res = await res() The former obviously breaks when somebody combines these idioms and calls run_callback(foo) but I can't help but wonder whether the latter use might be deprecated, or even warned about, in the future and/or with non-CPython implementations. -- -- Matthias Urlichs signature.asc Description: Digital signature ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com