目錄
結論
首頁 後端開發 Python教學 BlockBuster 簡介:我的非同步事件循環被封鎖了嗎?

BlockBuster 簡介:我的非同步事件循環被封鎖了嗎?

Jan 09, 2025 am 06:29 AM

Introducing BlockBuster: is my asyncio event loop blocked?

Python 3.5 引入了非同步 I/O 作為執行緒的替代方案來處理並發。非同步 I/O 和 Python 中的 asyncio 實現的優勢在於,透過不產生記憶體消耗大的作業系統線程,系統使用更少的資源並且更具可擴展性。此外,在 asyncio 中,調度點透過 await 語法明確定義,而在基於線程的並發中,GIL 可能會在難以預測的程式碼點釋放。因此,基於 asyncio 的並發系統更容易理解和調試。最終,可以取消 asyncio 任務,而這在使用執行緒時不容易做到。

但是,為了真正受益於這些優勢,在非同步協程中避免阻塞呼叫非常重要。阻塞呼叫可以是網路呼叫、檔案系統呼叫、sleep 呼叫等等。這些阻塞呼叫是有害的,因為在底層,asyncio 使用單執行緒事件循環來並發運行協程。因此,如果在協程中進行阻塞調用,它會阻塞整個事件循環和所有協程,從而影響應用程式的整體效能。

以下是一個阻塞呼叫阻止程式碼並發執行的範例:

import asyncio
import datetime
import time

async def example(name):
    print(f"{datetime.datetime.now()}: {name} start")
    time.sleep(1)  # time.sleep 是一个阻塞函数
    print(f"{datetime.datetime.now()}: {name} stop")

async def main():
    await asyncio.gather(example("1"), example("2"))

asyncio.run(main())
登入後複製
登入後複製

運行結果類似:

<code>2025-01-07 18:50:15.327677: 1 start
2025-01-07 18:50:16.328330: 1 stop
2025-01-07 18:50:16.328404: 2 start
2025-01-07 18:50:17.333159: 2 stop</code>
登入後複製
登入後複製

可以看到,兩個協程沒有並發運行。

為了克服這個問題,你需要使用非阻塞等效項或將執行延遲到執行緒池:

import asyncio
import datetime
import time

async def example(name):
    print(f"{datetime.datetime.now()}: {name} start")
    await asyncio.sleep(1)  # 将阻塞的 time.sleep 调用替换为非阻塞的 asyncio.sleep 协程
    print(f"{datetime.datetime.now()}: {name} stop")

async def main():
    await asyncio.gather(example("1"), example("2"))

asyncio.run(main())
登入後複製
登入後複製

運行結果類似:

<code>2025-01-07 18:53:53.579738: 1 start
2025-01-07 18:53:53.579797: 2 start
2025-01-07 18:53:54.580463: 1 stop
2025-01-07 18:53:54.580572: 2 stop</code>
登入後複製

這裡兩個協程並發運行。

現在的問題是,並不總是很容易識別一個方法是否阻塞。特別是如果程式碼庫很大或使用第三方函式庫。有時,阻塞呼叫是在程式碼的深層部分進行的。

例如,這段程式碼是否阻塞?

import blockbuster
from importlib.metadata import version

async def get_version():
    return version("blockbuster")
登入後複製

Python 是否在啟動時將包元資料載入記憶體?是在載入 blockbuster 模組時完成的嗎?或當我們呼叫 version() 時?結果是否被緩存,後續呼叫將是非阻塞的嗎?正確答案是在呼叫 version() 時完成的,它涉及讀取已安裝套件的 METADATA 檔案。且結果沒有被緩存。因此,version() 是一個阻塞調用,應該始終推遲到線程中。如果不深入研究 importlib 的程式碼,很難​​知道這個事實。

偵測阻塞呼叫的一種方法是啟動 asyncio 的偵錯模式來記錄耗時過長的阻塞呼叫。但這並不是最有效的方法,因為許多短於觸發超時時間的阻塞仍然會損害效能,並且測試/開發中的阻塞時間可能與生產環境中的阻塞時間不同。例如,如果資料庫必須獲取大量數據,則資料庫呼叫在生產環境中可能需要更長時間。

這就是 BlockBuster 發揮作用的地方!啟動後,BlockBuster 將修補幾個阻塞的 Python 框架方法,如果它們從 asyncio 事件循環調用,則會引發錯誤。預設修補的方法包括 osiotimesocketsqlite 模組的方法。有關 BlockBuster 偵測到的方法的完整列表,請參閱項目自述文件。然後,你可以在單元測試或開發模式中啟動 BlockBuster 來捕捉任何阻塞呼叫並修復它們。如果你知道 JVM 中很棒的 BlockHound 函式庫,它的原理相同,但適用於 Python。 BlockHound 是 BlockBuster 的一個很好的靈感來源,感謝創作者。

讓我們看看如何在上面阻塞程式碼片段上使用 BlockBuster。

首先,我們要安裝 blockbuster 套件

import asyncio
import datetime
import time

async def example(name):
    print(f"{datetime.datetime.now()}: {name} start")
    time.sleep(1)  # time.sleep 是一个阻塞函数
    print(f"{datetime.datetime.now()}: {name} stop")

async def main():
    await asyncio.gather(example("1"), example("2"))

asyncio.run(main())
登入後複製
登入後複製

然後,我們可以使用 pytest fixture 和 blockbuster_ctx() 方法來在每個測試開始時啟動 BlockBuster,並在拆卸期間停用它。

<code>2025-01-07 18:50:15.327677: 1 start
2025-01-07 18:50:16.328330: 1 stop
2025-01-07 18:50:16.328404: 2 start
2025-01-07 18:50:17.333159: 2 stop</code>
登入後複製
登入後複製

如果你用 pytest 運行這個,你會得到

import asyncio
import datetime
import time

async def example(name):
    print(f"{datetime.datetime.now()}: {name} start")
    await asyncio.sleep(1)  # 将阻塞的 time.sleep 调用替换为非阻塞的 asyncio.sleep 协程
    print(f"{datetime.datetime.now()}: {name} stop")

async def main():
    await asyncio.gather(example("1"), example("2"))

asyncio.run(main())
登入後複製
登入後複製

注意: 通常,在一個真實的項目中,blockbuster() fixture 將在一個 conftest.py 檔案中設定。

結論

我相信 BlockBuster 在 asyncio 專案中非常有用。它已經幫助我在我參與的專案中檢測到許多阻塞呼叫問題。但這並不是靈丹妙藥。特別是,有些第三方函式庫不使用 Python 框架方法來與網路或檔案系統交互,而是包裝 C 函式庫。對於這些庫,可以在測試設定中新增規則來觸發這些庫的阻塞呼叫。 BlockBuster 也是開源的:非常歡迎貢獻,以便在核心專案中為您的最喜歡的庫添加規則。如果你看到問題和可以改進的地方,我很樂意在專案問題追蹤器中收到你的回饋。

一些連結:

  • GitHub 專案
  • 問題
  • Pypi 上的包包

以上是BlockBuster 簡介:我的非同步事件循環被封鎖了嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1655
14
CakePHP 教程
1414
52
Laravel 教程
1307
25
PHP教程
1253
29
C# 教程
1228
24
Python vs.C:申請和用例 Python vs.C:申請和用例 Apr 12, 2025 am 12:01 AM

Python适合数据科学、Web开发和自动化任务,而C 适用于系统编程、游戏开发和嵌入式系统。Python以简洁和强大的生态系统著称,C 则以高性能和底层控制能力闻名。

您可以在2小時內學到多少python? 您可以在2小時內學到多少python? Apr 09, 2025 pm 04:33 PM

兩小時內可以學到Python的基礎知識。 1.學習變量和數據類型,2.掌握控制結構如if語句和循環,3.了解函數的定義和使用。這些將幫助你開始編寫簡單的Python程序。

Python:遊戲,Guis等 Python:遊戲,Guis等 Apr 13, 2025 am 12:14 AM

Python在遊戲和GUI開發中表現出色。 1)遊戲開發使用Pygame,提供繪圖、音頻等功能,適合創建2D遊戲。 2)GUI開發可選擇Tkinter或PyQt,Tkinter簡單易用,PyQt功能豐富,適合專業開發。

2小時的Python計劃:一種現實的方法 2小時的Python計劃:一種現實的方法 Apr 11, 2025 am 12:04 AM

2小時內可以學會Python的基本編程概念和技能。 1.學習變量和數據類型,2.掌握控制流(條件語句和循環),3.理解函數的定義和使用,4.通過簡單示例和代碼片段快速上手Python編程。

Python與C:學習曲線和易用性 Python與C:學習曲線和易用性 Apr 19, 2025 am 12:20 AM

Python更易學且易用,C 則更強大但複雜。 1.Python語法簡潔,適合初學者,動態類型和自動內存管理使其易用,但可能導致運行時錯誤。 2.C 提供低級控制和高級特性,適合高性能應用,但學習門檻高,需手動管理內存和類型安全。

Python和時間:充分利用您的學習時間 Python和時間:充分利用您的學習時間 Apr 14, 2025 am 12:02 AM

要在有限的時間內最大化學習Python的效率,可以使用Python的datetime、time和schedule模塊。 1.datetime模塊用於記錄和規劃學習時間。 2.time模塊幫助設置學習和休息時間。 3.schedule模塊自動化安排每週學習任務。

Python:探索其主要應用程序 Python:探索其主要應用程序 Apr 10, 2025 am 09:41 AM

Python在web開發、數據科學、機器學習、自動化和腳本編寫等領域有廣泛應用。 1)在web開發中,Django和Flask框架簡化了開發過程。 2)數據科學和機器學習領域,NumPy、Pandas、Scikit-learn和TensorFlow庫提供了強大支持。 3)自動化和腳本編寫方面,Python適用於自動化測試和系統管理等任務。

Python:自動化,腳本和任務管理 Python:自動化,腳本和任務管理 Apr 16, 2025 am 12:14 AM

Python在自動化、腳本編寫和任務管理中表現出色。 1)自動化:通過標準庫如os、shutil實現文件備份。 2)腳本編寫:使用psutil庫監控系統資源。 3)任務管理:利用schedule庫調度任務。 Python的易用性和豐富庫支持使其在這些領域中成為首選工具。

See all articles