Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Python's asyncio.coroutine be thought of as a generator?

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?

like image 570
item4 Avatar asked Apr 20 '15 15:04

item4


People also ask

Is coroutine a generator object?

Coroutines are Generators, but their yield accepts values. Coroutines can pause and resume execution (great for concurrency).

What differentiates a generator from a coroutine?

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.

What is Asyncio coroutine?

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.

What is an asynchronous generator in Python?

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.


1 Answers

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.

like image 193
dano Avatar answered Sep 25 '22 06:09

dano