国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

使用 Asyncio 進(jìn)行異步 Python 簡介

公平地說,大多數(shù)Hackers 和 Slackers讀者都有一個共同點(diǎn):我們喜歡用 Python 編寫東西。這并不使我們與眾不同;相反,我們是獨(dú)一無二的。它反映了一個眾所周知且易于解釋的現(xiàn)象,即數(shù)據(jù)科學(xué)家/工程師進(jìn)入(以及最近離開)以前為軟件工程保留的空間:多用途編程語言。盡管這些學(xué)科彼此之間有多么獨(dú)特,但我們有一個共同的特征。引用披頭士樂隊的話,我們需要的是 Python??。

然而,每一次旅程都有一個決定性的時刻,很明顯,這門語言已經(jīng)度過了它的30 歲生日。自 Guido 釋放 Serpent 來解決1991 年的問題以來,已經(jīng)過去了三十年。這是冷戰(zhàn)時代的最后一年:歷史上的一個不同時期,在計算領(lǐng)域更是如此。Python 背后的大多數(shù)設(shè)計決策在當(dāng)時都是明智的,但其中一些決策已成為當(dāng)今的“怪癖”。最具爭議性的怪癖很容易就是并發(fā)話題。

事實上,我指的是全局解釋器鎖(GIL)。我會讓你免去貶低 GIL 的痛苦,因為其他人在這方面做得比我好得多(如果你對細(xì)節(jié)感興趣并且有時間,我強(qiáng)烈推薦一篇題為The GIL 的文章,以及它對 Python 多線程的影響)。GIL 的長處和短處在于它限制了 Python 有效利用多個 CPU 核心,讓您的 8 核筆記本電腦在單個核心上運(yùn)行 Python 腳本,而其他核心則閑置。

并發(fā)性是一個遠(yuǎn)遠(yuǎn)超出 Python 范圍的復(fù)雜問題。大多數(shù)編程語言都有相似的命運(yùn)。但我們來這里并不是為了哀嘆我們的處境;而是為了我們的處境。我們在這里討論異步 I/O。

在 Python 中同時做多件事

并發(fā)是編程中的一個廣泛概念,可以歸結(jié)為“同時做一堆事情”。并發(fā)運(yùn)行的代碼通常采用兩種可能的形式之一:

  1. 任務(wù)輪流執(zhí)行,以盡量減少同事任務(wù)的停機(jī)時間。

  2. 真正并行的任務(wù)同時并行運(yùn)行。

Python 附帶了兩個模塊,分別處理這兩種方法:

  • 線程(單進(jìn)程):Python 的線程模塊僅限于在給定時間使用單個處理器。線程模塊可以管理占用給定線程的任務(wù)。任務(wù) X 一直運(yùn)行,直到被外部因素阻止(例如等待對 HTTP 請求的響應(yīng))。同時,任務(wù) Y 優(yōu)先執(zhí)行它,直到任務(wù) X 準(zhǔn)備好繼續(xù)(因此“阻塞 I/O”)。

  • 多處理(多個處理器):多處理模塊使代碼能夠并行運(yùn)行。腳本被初始化并在n 個CPU上同時運(yùn)行n次。將單條道路擴(kuò)展為 8 車道高速公路具有明顯的性能優(yōu)勢,直到需要整合每項任務(wù)的結(jié)果為止。多個進(jìn)程無法同時將數(shù)據(jù)寫入同一目標(biāo)(數(shù)據(jù)庫、文件等)而不創(chuàng)建相互阻塞的鎖。對于旨在產(chǎn)生輸出的腳本來說,嘗試解決這個問題幾乎肯定是一項難以克服的努力。

Asyncio 適用于哪里?

Asyncio是上述方法的第三種也是通常首選的替代方法。盡管僅限于單個線程,Asyncio可以比 Python 的本機(jī)單線程執(zhí)行速度快得多地執(zhí)行大量操作。為了說明這是如何可能的,請考慮人類如何傾向于“同時處理多項任務(wù)”。當(dāng)人們聲稱自己是“多任務(wù)處理”時,他們通常是通過在任務(wù)之間切換來完成工作,而不是同時做多件事。單線程程序以同樣的方式異步:通過重疊工作來優(yōu)化輸出。

雖然人類在多任務(wù)處理方面表現(xiàn)不佳是出了名的,但機(jī)器可以從這種做法中看到顯著的性能優(yōu)勢。它們通常更適合在沒有額外開銷的情況下啟動和停止工作。這個概念是FastAPI等框架的“秘密武器” ,F(xiàn)astAPI 是一個異步 Python 框架,它自稱性能“與NodeJS和Go相當(dāng) ” (我保證下次會在 FastAPI 上寫一篇公平的文章)。

我花了一段時間才打消了我的懷疑,即單個線程如何同時處理多個任務(wù)可以提供值得一寫的性能優(yōu)勢。直到我偶然發(fā)現(xiàn)事件循環(huán)的概念,事情才開始有意義。

事件循環(huán)

我們從積壓的 I/O“任務(wù)”開始。它們可以是 HTTP 請求,將內(nèi)容保存到磁盤,或者在我們的例子中,兩者的混合。同步 Python 工作流程(讀作:標(biāo)準(zhǔn) Python)將從開始到結(jié)束一次執(zhí)行一項任務(wù)。這就像在車管所排隊等候,那里只有一根線,而這位女士討厭你們所有人。

事件循環(huán)以不同的方式處理事情,以便更快地完成任務(wù)。給定許多任務(wù),事件“循環(huán)”通過獲取新任務(wù)并將它們委托給線程來工作。該循環(huán)不斷檢查正在進(jìn)行的任務(wù)是否有停機(jī)(或完成)。當(dāng)委派任務(wù)“等待”外部因素(例如 HTTP 請求)時,事件循環(huán)會通過啟動線程中的另一個任務(wù)來填充死區(qū)時間。如果事件循環(huán)發(fā)現(xiàn)分配的任務(wù)已完成,則該任務(wù)將從其線程中刪除,收集該任務(wù)的輸出,并且循環(huán)從隊列中選擇另一個任務(wù)來占用該線程:


異步 I/O 事件循環(huán)

異步 I/O 事件循環(huán)

與 DMV 線路不同,事件循環(huán)的工作方式與餐廳有些相似(請繼續(xù)我的說法)。盡管有許多桌子和一個廚房,但服務(wù)器通過在桌子(任務(wù))和廚房(線程)之間輪換來處理“積壓”。在廚房里連續(xù)準(zhǔn)備多個食物訂單比接受單個訂單并等待它們被創(chuàng)建/提供給下一個顧客之前要高效得多。

協(xié)程:異步運(yùn)行的函數(shù)

異步 Python 腳本不定義函數(shù)- 它們定義協(xié)程。協(xié)程(用 定義async def,而不是def)可以在完成之前停止執(zhí)行,通常等待另一個協(xié)程完成。下面的代碼片段演示了協(xié)程的最簡單示例:

"""Define a Coroutine function to be executed asynchronously."""
import asyncio

from logger import LOGGER


async def simple_coroutine(number: int):
    """
    Wait for a time delay & display number associated with coroutine.

    :param int number: Number to identify the current coroutine.
    """
    await asyncio.sleep(1)
    LOGGER.info(f"Coroutine {number} has finished executing.")

協(xié)程.py

simple_coroutine()在記錄消息之前暫停執(zhí)行 1 秒。協(xié)程不能像常規(guī)函數(shù)那樣被調(diào)用;除非在 asyncio 事件循環(huán)內(nèi)運(yùn)行,否則嘗試運(yùn)行simple_coroutine(1)將不起作用。幸運(yùn)的是,創(chuàng)建事件循環(huán)很容易:

import asyncio

from coroutines import simple_coroutine  # Import our coroutine


asyncio.run(simple_coroutine(1))

運(yùn)行協(xié)程

asyncio.run()創(chuàng)建一個事件循環(huán),并運(yùn)行傳遞給它的協(xié)程。當(dāng)您的腳本有一個所有邏輯源自的入口點(diǎn)時,創(chuàng)建事件循環(huán)是最好的?;蛘撸琣syncio.gather()如果您只想執(zhí)行少量協(xié)程,則可以接受任意數(shù)量的協(xié)程:

import asyncio

from coroutines import simple_coroutine  # Import our coroutine


asyncio.gather(
    simple_coroutine(1)
    simple_coroutine(2)
    simple_coroutine(3)
)

 在事件循環(huán)內(nèi)運(yùn)行 3 個協(xié)程

運(yùn)行此腳本將執(zhí)行所有三個協(xié)程并記錄以下內(nèi)容:

1
2
3

asyncio.gather()三個協(xié)程的輸出

您認(rèn)為完成上述操作需要多長時間?3秒,也許?或者我們是否能夠通過魔法來優(yōu)化我們的代碼?

您可能會驚訝地發(fā)現(xiàn),運(yùn)行上述代碼始終能在幾乎一秒內(nèi)執(zhí)行(或者在糟糕的一天偶爾會執(zhí)行1.01 秒)。如果我們使用 Python 的內(nèi)置time.perf_counter()來計算函數(shù)的執(zhí)行時間,我們可以直接看到這一點(diǎn):

import asyncio
import time

from coroutines import simple_coroutine  # Import our coroutine


def async_gather_example()
    start_time = time.perf_counter()
    asyncio.gather(
        simple_coroutine(1)
        simple_coroutine(2)
        simple_coroutine(3)
    )
    print(
        f"Executed {__name__} in {time.perf_counter() - start_time:0.2f} seconds."
    )


async_example()

跟蹤執(zhí)行 3 個休眠 1 秒的協(xié)程的執(zhí)行時間

果然,該腳本幾乎只花了1 秒:

Executed async_example in 1.01 seconds.

輸出async_example()

我們的協(xié)程simple_coroutine()需要 1 秒才能自行執(zhí)行。上面令人印象深刻的是,我們調(diào)用了這個協(xié)程 3 次,運(yùn)行時間接近 1 秒,而同步Python 腳本確實需要 3 秒。更重要的是,執(zhí)行這些任務(wù)的開銷僅不到.01幾秒,這意味著我們的協(xié)程幾乎同時完成。

使用任務(wù)

asyncio.gather()在上面的示例中,我們回避了 Asyncio 中的一個基本數(shù)據(jù)結(jié)構(gòu):Task.

協(xié)程是可以異步運(yùn)行的函數(shù)。當(dāng)以特定方式運(yùn)行數(shù)百或數(shù)千個此類函數(shù)時,如果能夠“管理”這些函數(shù),那就太好了。了解協(xié)程何時失?。ㄒ约叭绾翁幚硭?,或者只是檢查循環(huán)當(dāng)前正在處理哪個協(xié)程,特別是當(dāng)我們的事件循環(huán)可能需要幾分鐘或幾小時才能執(zhí)行或有可能失敗時。

管理任務(wù)

在更復(fù)雜的工作流程中,任務(wù)提供了幾種有用的方法來幫助我們管理正在執(zhí)行的任務(wù):

  • .set_name([name])(和.get_name()):為任務(wù)命名,以便以人類可讀的方式來識別哪個任務(wù)。

  • .cancel(msg=[message]):取消事件循環(huán)中的任務(wù),允許循環(huán)繼續(xù)執(zhí)行其他任務(wù)。對于無響應(yīng)或不太可能完成的任務(wù)很有用。

  • .canceled():返回True任務(wù)是否被取消,否則False返回。

  • .done():返回True任務(wù)是否成功完成,否則False返回。

  • .result():返回任務(wù)的結(jié)果。canceled任務(wù)將包含有關(guān)任務(wù)被取消原因的異常消息,而done任務(wù)將僅返回done。尚未調(diào)用的任務(wù)將返回InvalidStateError異常。

  • 許多其他方法都可以在Asyncio 的 Task 文檔中找到。

創(chuàng)建任務(wù)

Coroutine使用 Asyncio包裝sTask很簡單。之前的運(yùn)行asyncio.gather()為我們解決了這個問題,但這只是一種捷徑,使我們無法利用任務(wù)的優(yōu)勢,因為任務(wù)被實例化為通用對象并立即執(zhí)行。如果我們事先創(chuàng)建任務(wù),我們可以將元數(shù)據(jù)與它們關(guān)聯(lián)起來,并在準(zhǔn)備好時在事件循環(huán)中執(zhí)行它們。

我們將創(chuàng)建一個名為 的新協(xié)程  create_tasks(),該協(xié)程將:

  • 創(chuàng)建n 個Task 實例simple_coroutine()。

  • 在創(chuàng)建時為每個任務(wù)分配一個名稱。

  • 以 Python 列表的形式返回所有任務(wù),稍后可以通過事件循環(huán)執(zhí)行:

"""Create multiple tasks from a Coroutine."""
import asyncio
from asyncio import Task
from typing import List

from logger import LOGGER

from asyncio_intro_part1.coroutines import simple_coroutine


async def create_tasks(num_tasks: int) -> List[Task]:
    """
    Create n number of asyncio tasks to be executed.

    :param int num_tasks: Number of tasks to create.

    :returns: List[Task]
    """
    task_list = []
    LOGGER.info(f"Creating {num_tasks} tasks to be executed...")
    for i in range(num_tasks):
        task = asyncio.create_task(
            simple_coroutine(i),
            name=f"Task #{i}"
        )
        task_list.append(task)
        LOGGER.info(f"Created Task: {task}")
    return task_list

任務(wù).py

行動中的任務(wù)

定義了我們的create_tasks()方法后,就到了有趣的部分了:查看任務(wù)的創(chuàng)建、執(zhí)行和完成。在項目的根部,我們將定義最后一個函數(shù)async_tasks_example()來演示這一點(diǎn):

...
from .tasks import create_tasks


async def async_tasks_example():
    """Create and inspect tasks to wrap simple functions."""
    task_list = await create_tasks(5)
    done, pending = await asyncio.wait(task_list)
    if done:
        LOGGER.success(
            f"{len(done)} tasks completed: {[task.get_name() for task in done]}."
        )
    if pending:
        LOGGER.warning(
            f"{len(done)} tasks pending: {[task.get_name() for task in pending]}."
        )

  __init__.py

我們首先將通過創(chuàng)建的 5 個任務(wù)分配create_tasks()給該task_list變量。發(fā)生這種情況時,我們會看到在tasks.py中添加的正確日志記錄:

17:00:53 PM | INFO: Creating 5 tasks to be executed...

17:00:53 PM | INFO: Created Task: <Task pending name='Task #0' coro=<simple_coroutine() running at /Users/toddbirchard/Projects/asyncio-tutorial-part1/asyncio_intro_part1/coroutines.py:7>>

17:00:53 PM | INFO: Created Task: <Task pending name='Task #1' coro=<simple_coroutine() running at /Users/toddbirchard/Projects/asyncio-tutorial-part1/asyncio_intro_part1/coroutines.py:7>>

17:00:53 PM | INFO: Created Task: <Task pending name='Task #2' coro=<simple_coroutine() running at /Users/toddbirchard/Projects/asyncio-tutorial-part1/asyncio_intro_part1/coroutines.py:7>>

17:00:53 PM | INFO: Created Task: <Task pending name='Task #3' coro=<simple_coroutine() running at /Users/toddbirchard/Projects/asyncio-tutorial-part1/asyncio_intro_part1/coroutines.py:7>>

17:00:53 PM | INFO: Created Task: <Task pending name='Task #4' coro=<simple_coroutine() running at /Users/toddbirchard/Projects/asyncio-tutorial-part1/asyncio_intro_part1/coroutines.py:7>>

在tasks.py中創(chuàng)建5個任務(wù)的輸出

我們隨后通過 執(zhí)行這五個任務(wù)asyncio.wait(task_list)。asyncio.wait()嘗試完成 task_list 中的所有任務(wù)并返回“已完成”和“待處理”任務(wù)的元組。由于添加了一些日志記錄和任務(wù)名稱的存在,我們可以確認(rèn)所有任務(wù)均已成功完成:文章來源地址http://www.zghlxwxcb.cn/article/583.html

17:00:54 PM | INFO: Coroutine 0 has finished executing.
17:00:54 PM | INFO: Coroutine 1 has finished executing.
17:00:54 PM | INFO: Coroutine 2 has finished executing.
17:00:54 PM | INFO: Coroutine 3 has finished executing.
17:00:54 PM | INFO: Coroutine 4 has finished executing.
17:00:54 PM | SUCCESS: 5 tasks completed: ['Task #1', 'Task #4', 'Task #3', 'Task #0', 'Task #2'].

到此這篇關(guān)于使用 Asyncio 進(jìn)行異步 Python 簡介的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

原文地址:http://www.zghlxwxcb.cn/article/583.html

如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請聯(lián)系站長進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Python異步編程探究:深入理解asyncio的使用和原理【第130篇—asyncio】

    Python異步編程探究:深入理解asyncio的使用和原理【第130篇—asyncio】

    前些天發(fā)現(xiàn)了一個巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家?!军c(diǎn)擊進(jìn)入巨牛的人工智能學(xué)習(xí)網(wǎng)站】。 隨著計算機(jī)應(yīng)用程序的復(fù)雜性不斷增加,對于高效處理I/O密集型任務(wù)的需求也越來越迫切。在Python中,asyncio模塊提供了一種強(qiáng)大的異步編程

    2024年04月12日
    瀏覽(30)
  • Python asyncio高性能異步編程 詳解

    Python asyncio高性能異步編程 詳解

    目錄 一、協(xié)程 1.1、greenlet實現(xiàn)協(xié)程 1.2、yield 1.3、asyncio 1.4、async await 二、協(xié)程意義 三、異步編程 3.1、事件循環(huán) 3.2、快速上手 3.3、await 3.4、Task對象 3.5、asyncio.Future對象 3.5、concurrent.futures.Future對象 3.7、異步迭代器 3.8、異步上下文管理器 四、uvloop 五、實戰(zhàn)案例

    2024年02月20日
    瀏覽(33)
  • Asyncio 協(xié)程異步筆記

    協(xié)程不是計算機(jī)提供,而是程序員人為創(chuàng)造。 協(xié)程(coroutine),也可以被稱為微線程,是一種用戶態(tài)內(nèi)的上下文切換技術(shù)。簡而言之,其實就是通過一個線程實現(xiàn)代碼塊互相切換運(yùn)行。例如: 實現(xiàn)協(xié)程有這么幾種方法: greenlet ,早期模塊。 yield 。 asyncio 裝飾器(py

    2024年02月08日
    瀏覽(18)
  • 6. Python使用Asyncio開發(fā)TCP服務(wù)器簡單案例

    1. 說明 在Python中開發(fā)TCP/IP服務(wù)器有兩種方式,一種使用Socket,需要在py文件中引入對應(yīng)的socket包,這種方式只能執(zhí)行單項任務(wù);另一種方式使用Asyncio異步編程,可以一次創(chuàng)建多個服務(wù)器執(zhí)行不同的任務(wù)。 2. 接口說明 3. 簡單案例 創(chuàng)建一個tcp服務(wù)器,并實現(xiàn)數(shù)據(jù)的接受和發(fā)送

    2024年03月11日
    瀏覽(28)
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)實現(xiàn)異步攝像頭轉(zhuǎn)碼服務(wù)器

    (aiohttp-asyncio-FFmpeg-Docker-SRS)實現(xiàn)異步攝像頭轉(zhuǎn)碼服務(wù)器

    在先前的博客文章中,我們已經(jīng)搭建了一個基于SRS的流媒體服務(wù)器?,F(xiàn)在,我們希望通過Web接口來控制這個服務(wù)器的行為,特別是對于正在進(jìn)行的 RTSP 轉(zhuǎn)碼任務(wù)的管理。這將使我們能夠在不停止整個服務(wù)器的情況下,動態(tài)地啟動或停止攝像頭的轉(zhuǎn)碼過程。 Docker部署 SRS rtmp/f

    2024年02月02日
    瀏覽(24)
  • chatgpt|安裝及示例|聊天|嵌入|微調(diào)|適度|圖像|音頻|異步|API 錯誤代碼-OpenAI Python庫簡介

    chatgpt|安裝及示例|聊天|嵌入|微調(diào)|適度|圖像|音頻|異步|API 錯誤代碼-OpenAI Python庫簡介

    項目git地址 OpenAI Python 庫提供了對 OpenAI API 的便捷訪問來自用 Python 語言編寫的應(yīng)用程序。它包括一個用于初始化的 API 資源的預(yù)定義類集自己從 API 響應(yīng)動態(tài)地使其兼容具有廣泛版本的 OpenAI API。 您可以在官方的網(wǎng)站中找到 OpenAI Python 庫的使用示例 API reference and the OpenAI Coo

    2023年04月15日
    瀏覽(22)
  • Python潮流周刊#7:我討厭用 asyncio

    你好,我是貓哥。這里記錄每周值得分享的 Python 及通用技術(shù)內(nèi)容,部分為英文,已在小標(biāo)題注明。(標(biāo)題取自其中一則分享,不代表全部內(nèi)容都是該主題,特此聲明。) 首發(fā)于我的博客:https://pythoncat.top/posts/2023-06-17-weekly7 1、AsyncIO (英) 文章的作者討厭 asyncio 庫,認(rèn)為使用

    2024年02月09日
    瀏覽(27)
  • 【微信小程序】使用 wx.request 方法進(jìn)行異步網(wǎng)絡(luò)請求

    在微信小程序中,你可以使用 wx.request 方法進(jìn)行異步網(wǎng)絡(luò)請求,并將獲取到的列表數(shù)據(jù)渲染到 UI 上。 首先,在頁面的 data 中定義一個數(shù)組變量,用于存儲獲取到的列表數(shù)據(jù),例如: 然后,在頁面的生命周期函數(shù) onLoad 或需要觸發(fā)網(wǎng)絡(luò)請求的函數(shù)中,使用 wx.request 方法發(fā)送異

    2024年02月16日
    瀏覽(42)
  • 使用 Clojure 進(jìn)行 OpenCV 開發(fā)簡介

    使用 Clojure 進(jìn)行 OpenCV 開發(fā)簡介

    從 OpenCV 2.4.4 開始,OpenCV 支持使用與 Android 開發(fā)幾乎相同的接口進(jìn)行桌面 Java 開發(fā)。 Clojure?是由 Java 虛擬機(jī)托管的一種現(xiàn)代 LISP 方言,它提供了與底層 JVM 的完全互操作性。這意味著我們甚至應(yīng)該能夠使用 Clojure REPL(Read Eval Print Loop)作為底層 OpenCV 引擎的交互式可編程接口

    2024年01月16日
    瀏覽(17)
  • Python向帶有SSL/TSL認(rèn)證服務(wù)器發(fā)送網(wǎng)絡(luò)請求小實踐(附并發(fā)http請求實現(xiàn)asyncio+aiohttp)

    Python向帶有SSL/TSL認(rèn)證服務(wù)器發(fā)送網(wǎng)絡(luò)請求小實踐(附并發(fā)http請求實現(xiàn)asyncio+aiohttp)

    最近工作中遇到這樣的一個場景:給客戶發(fā)送文件的時候,為保證整個過程中,文件不會被篡改,需要在發(fā)送文件之間, 對發(fā)送的文件進(jìn)行簽名, 而整個簽名系統(tǒng)是另外一個團(tuán)隊做的, 提供了一個接口服務(wù)完成簽名,但訪問這個接口需要提供他們團(tuán)隊提供的證書鏈先進(jìn)行認(rèn)

    2024年04月16日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包