簡體   English   中英

這是一個協程怎么樣?

[英]How is this a coroutine?

我試圖理解Python中的協同程序(一般而言)。 一直在閱讀關於理論,概念和一些例子,但我仍然在苦苦掙扎。 我理解異步模型(做了一些Twisted)但不是協同程序。

一個教程將此作為一個協程示例(我做了一些更改來說明我的問題):

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

這與此一起運行

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

查看生成器協同程序示例,我可以看到一些yield語句。 這里什么也沒有,urllib是同步的,AFAIK。

此外,由於代碼應該是異步的,我期待看到一系列交錯的數字。 (1,4,5,1,2,......,“完成”,......)。 我所看到的是一個單一的數字重復結束在一個Finished ,然后另一個(3,3,3,3,......“完成”,1,1,1,1,......,“完成”。 ..)。

在這一點上,我很想說教程是錯誤的,這只是一個協程,因為前面有異步。

協程 共同代表合作 屈服(對其他例程)使例程成為一個共同例程,實際上,因為只有在等待時才能讓其他協同例程交錯。 在Python 3.5及更高版本的新async世界中,通常是通過await來自其他協同程序的結果來實現的。

根據該定義,您找到的代碼不是協程。 Python而言,它是一個協程對象 ,因為這是使用async def創建的函數對象的類型。

所以,是的,教程是無益的,因為他們在協程函數中使用了完全同步的,不合作的代碼。

而不是urllib ,將需要異步HTTP庫。 aiohttp

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

在等待建立連接時,以及等待更多網絡數據時,以及再次關閉會話時,此協程可以產生其他例程。

我們可以進一步使文件寫入異步,但這有可移植性問題 ; aiofiles項目庫使用線程來卸載阻塞調用。 使用該庫,代碼需要更新為:

import aiofiles

async with aiofiles.open(filename, 'wb') as fd:
    while True:
        chunk = await resp.content.read(1024)
        if not chunk:
            break
        await fd.write(chunk)

注意 :此博客帖子已更新以解決這些問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM