I googled python coroutine
, and saw only generators (Almost almost all the examples use yield
without asyncio
.)
Are they really the same?
What is the difference between asyncio.coroutine
and a generator?
Coroutines are Generators, but their yield accepts values. Coroutines can pause and resume execution (great for concurrency).
A generator is essentially a cut down (asymmetric) coroutine. The difference between a coroutine and generator is that a coroutine can accept arguments after it's been initially called, whereas a generator can't.
Asyncio is a programming design that achieves concurrency without multi-threading. It is a single-threaded, single-process design. It uses cooperative multitasking, i.e., it gives a sense of concurrency despite using a single thread in a single process.
September 22, 2021 ‐ 1 min read. Asynchronous generator functions are part of Python version 3.6, they were introduced by PEP-525. Asynchronous generator functions are much like regular asynchronous functions except that they contain the yield keyword in the function body.
Most coroutine implementations in Python (including those provided by asyncio
and tornado
) are implemented using generators. This has been the case since PEP 342 - Coroutines via Enhanced Generators made it possible to send values into running generator objects, which enabled the implementation simple coroutines. Coroutines technically are generators, they're just designed to be used in a very different way. In fact, the PEP for asyncio
explicitly states this:
A coroutine is a generator that follows certain conventions.
asyncio.coroutine
is a generator. Quite literally:
>>> import asyncio
>>> @asyncio.coroutine
... def mycoro():
... yield from asyncio.sleep(1)
...
>>> a = mycoro()
>>> a
<generator object mycoro at 0x7f494b5becf0>
The difference, again, is in how the two things are meant to be used. Trying to iterate over a asyncio.coroutine
like an ordinary generator will not work:
>>> next(a)
Future<PENDING>
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in mycoro
File "/usr/lib/python3.4/asyncio/tasks.py", line 548, in sleep
return (yield from future)
File "/usr/lib/python3.4/asyncio/futures.py", line 349, in __iter__
assert self.done(), "yield from wasn't used with future"
AssertionError: yield from wasn't used with future
Clearly, you're not meant to iterate over it. You're only meant to yield from
it, or register it with the asyncio
event loop using asyncio.create_task
or asyncio.async
.
As I mentioned earlier, it's been possible to implement coroutines using generators since PEP 342, which was long before asyncio
or yield from
came along; that feature was added back in 2005. asyncio
and yield from
just add features that make writing coroutines easier.
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