How is this a coroutine?
<p>I'm trying to understand the coroutines in Python (and in general). Been reading about the theory, the concept and a few examples, but I'm still struggling. I understand the asynchronous model (did a bit of Twisted) but not coroutines yet.</p>

<p>One <a href="http://www.blog.pythonlibrary.org/2016/07/26/python-3-an-intro-to-asyncio/" rel="nofollow">tutorial</a> gives this as a coroutine example (I made a few changes to illustrate my problem):</p>

<pre><code>async def download_coroutine(url, number):
    """
    A coroutine to download the specified url
    """
    request = urllib.request.urlopen(url)
    filename = os.path.basename(url)
    print("Downloading %s" % url)

    with open(filename, 'wb') as file_handle:
        while True:
            print(number) # prints numbers to view progress
            chunk = request.read(1024)
            if not chunk:
                print("Finished")
                break
            file_handle.write(chunk)
    msg = 'Finished downloading {filename}'.format(filename=filename)
    return msg
</code></pre>

<p>This is run with this</p>

<pre><code>coroutines = [download_coroutine(url, number) for number, url in enumerate(urls)]
completed, pending = await asyncio.wait(coroutines)
</code></pre>

<p>Looking at generator coroutines examples I can see a few <code>yield</code> statements. There's nothing here, and urllib is synchronous, AFAIK.</p>

<p>Also, since the code is supposed to be asynchronous, I am expecting to see a series of interleaved numbers. (1, 4, 5, 1, 2, ..., "Finished", ...) . What I'm seeing is a single number repeating ending in a <code>Finished</code> and then another one (3, 3, 3, 3, ... "Finished", 1, 1, 1, 1, ..., "Finished" ...).</p>

<p>At this point I'm tempted to say the tutorial is wrong, and this is a coroutine just because is has async in front.</p>

<p>The <em>co</em> in <em>coroutine</em> stands for <em>cooperative</em>. Yielding (to other routines) makes a routine a co-routine, really, because only by yielding when waiting can other co-routines be interleaved. In the new <code>async</code> world of Python 3.5 and up, that usually is achieved by <code>await</code>-ing results from other coroutines.</p>

<p>By that definition, the code you found is <em>not</em> a coroutine. As far as <em>Python</em> is concerned, it is a coroutine <em>object</em>, because that's the type given to a function object created using <code>async def</code>.</p>

<p>So yes, the tutorial is.. unhelpful, in that they used entirely synchronous, uncooperative code inside a coroutine function.</p>

<p>Instead of <code>urllib</code>, an asynchronous HTTP library would be needed. Like <a href="http://aiohttp.readthedocs.io/en/stable/" rel="nofollow"><code>aiohttp</code></a>:</p>

<pre><code>import aiohttp

async def download_coroutine(url):
    """
    A coroutine to download the specified url
    """
    filename = os.path.basename(url)
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            with open(filename, 'wb') as fd:
                while True:
                    chunk = await resp.content.read(1024)
                    if not chunk:
                        break
                    fd.write(chunk)
    msg = 'Finished downloading {filename}'.format(filename=filename)
    return msg
</code></pre>

<p>This coroutine can yield to other routines when waiting for a connection to be established, and when waiting for more network data, as well as when closing the session again.</p>

python python-3.x async-await coroutine