Reputation: 885
I've heard that the @asyncio.coroutine
version of coroutine will eventually be deprecated in Python (maybe after 3.8?), and that only async def
will be supported. Today I use the decorator version in order to be able to just yield
(not yield from
another coroutine), because I'm waiting for some change (polling inside e.g. a while
loop) or to split up big portions of time-consuming blocking code into smaller chunks (and thus improve the concurrency experience).
Here is a minimal example:
import asyncio
@asyncio.coroutine
def foo(l):
print('entering foo')
while l[0] == 0:
yield
print('leaving foo')
async def bar(l):
print('entering bar')
await asyncio.sleep(1)
l[0] = 1
await asyncio.sleep(1)
print('leaving bar')
async def main():
l = [0]
t0 = asyncio.ensure_future(foo(l))
t1 = asyncio.ensure_future(bar(l))
await t0
await t1
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
This will print the following:
entering foo
entering bar
# foo is polling
# 1 second elapses
leaving foo
# 1 second elapses
leaving bar
How can we achieve that in an async def
version of coroutine? Should we use await asyncio.sleep(0)
?
Upvotes: 4
Views: 333
Reputation: 39546
await asyncio.sleep(0)
can be used to do what you want, but in current case it's not a good solution. Event loop would need to return into foo
every "tick" of it's execution: it wastes CPU resources.
When you want to wait for something to happen inside a coroutine proper way is to use asyncio.Event:
async def foo(event):
print('entering foo')
await event.wait()
print('leaving foo')
async def bar(event):
print('entering bar')
await asyncio.sleep(1)
event.set()
await asyncio.sleep(1)
print('leaving bar')
async def main():
event = asyncio.Event()
t0 = asyncio.ensure_future(foo(event))
t1 = asyncio.ensure_future(bar(event))
await t0
await t1
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
This way event loop will return into foo
only once: when event
is actually has been set.
Upvotes: 4
Reputation: 885
Yes, I think that await asyncio.sleep(0)
is the proper way to do it, see https://github.com/python/asyncio/issues/284. So foo
becomes:
async def foo(l):
print('entering foo')
while l[0] == 0:
await asyncio.sleep(0)
print('leaving foo')
Upvotes: 1