I've been mucking around with asyncio recently, and while I'm beginning to get an intuition for how it works, there's something that I've not been able to do. I'm not sure if it's because I've got the construction wrong, or if there's a reason why what I'm trying to do doesn't make sense.
In short, I want to be able to iterate over a yielding asyncio.coroutine. For example, I'd like to be able to do something like:
@asyncio.coroutine
def countdown(n):
while n > 0:
yield from asyncio.sleep(1)
n = n - 1
yield n
@asyncio.coroutine
def do_work():
for n in countdown(5):
print(n)
loop.run_until_complete(do_work())
However, this throws an exception from the bowels of asyncio. I've tried other things, like for n in (yield from countdown(5)): ...
but that also gives a similarly opaque runtime exception.
I can't immediately see why you shouldn't be do something like this, but I'm getting to the limits of my ability to understand what's going on.
So:
Let me know if this question's not clear!
coroutine" decorator is deprecated since Python 3.8, use "async def" instead · Javascript Required. Kindly enable Javascript. Updates · Content Removed.
asyncio. get_event_loop() Get the current event loop. If there is no current event loop set in the current OS thread, the OS thread is main, and set_event_loop() has not yet been called, asyncio will create a new event loop and set it as the current one.
The alternative way of starting up your event loop is to call the run_forever() method which will subsequently start your asyncio based event loop and have it run indefinitely until the program comes to an end or the stop() method is called.
In asyncio coroutines you should to use yield from
and never yield
.
That's by design. Argument for yield from
should be another coroutine or asyncio.Future
instance only.
Calls of coroutine itself should be used with yield from
again like yield from countdown(5)
.
For your case I recommend using queues:
import asyncio
@asyncio.coroutine
def countdown(n, queue):
while n > 0:
yield from asyncio.sleep(1)
n = n - 1
yield from queue.put(n)
yield from queue.put(None)
@asyncio.coroutine
def do_work():
queue = asyncio.Queue()
asyncio.async(countdown(5, queue))
while True:
v = yield from queue.get()
if v:
print(v)
else:
break
asyncio.get_event_loop().run_until_complete(do_work())
Well, you can use check for values yielded by countdown
, the following example works. But I think it is antipattern:
Too easy to make a mess
You anyway cannot compose countdown
calls with, say, itertools
functions. I mean something like sum(countdown(5))
or itertools.accumulate(countdown(5))
.
Anyway, example with mixing yield
and yield from
in coroutine:
import asyncio
@asyncio.coroutine
def countdown(n):
while n > 0:
yield from asyncio.sleep(1)
n = n - 1
yield n
@asyncio.coroutine
def do_work():
for n in countdown(5):
if isinstance(n, asyncio.Future):
yield from n
else:
print(n)
asyncio.get_event_loop().run_until_complete(do_work())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With