是的,我已經停止在這裡發布,但從行銷的角度來看,最好繼續發布......我們繼續。
文本最初發佈於此處。
本文的目的是直接總結理解 Python 語言中的並行性所需的基本概念。我建議您了解該主題的最低背景知識,或將本文與其他來源的研究結合。所有參考資料均在文末。
我將涵蓋以下主題:
在計算中,進程是正在運行的應用程式的實例。如果您在電腦上開啟一個應用程式(例如瀏覽器),該應用程式將與某個進程關聯。一個流程由以下部分組成:
以下圖片取自 Francis Machado 和 Luis Maia 的書:
此資訊是執行程序所必需的。
執行緒是程式的子例程,是作業系統管理的最小執行單元,也是行程的元件。
假設進程的各個執行緒可以並發執行(我們很快就會理解),共享記憶體等資源。不同的進程不共享這些資源。
下圖取自維基百科:
解釋上圖,我們可以得出,一個程式保存在磁碟(輔助非揮發性記憶體)上,包含多個指令,並且可以在一個或多個進程中實例化(啟動),而這些又可以具有幾個相關的線程。
這兩個表達在有關競爭的討論中出現很多,並且可以在葡萄牙語中與 I/O(輸入/輸出)和 CPU(中央處理單元)一起出現。
當我們談論 I/O 限制和 CPU 限制時,我們談論的是阻止操作在電腦上更快運行的限制因素,我們可以在同一程式碼庫中找到這兩種類型的操作。
CPU 密集型操作是 CPU 密集型操作,如果 CPU 更強大,運行速度會更快。換句話說,如果我們將時脈速度從 2GHz 提高到 4GHz,那麼該操作可能會運行得更快。我們在這裡討論的是執行許多計算、計算的操作;例如,如何計算 Pi。
I/O 綁定操作取決於網路速度以及輸入和輸出設備的速度。向 Web 伺服器發出請求或從磁碟讀取檔案是 I/O 綁定操作。
兩種類型的操作都可以從並發的使用中受益。
GIL 代表全域解釋器鎖,旨在防止一個Python 程序同時執行多個Python 指令字節碼。要執行一個線程,必須「取得」GIL,而當一個線程持有 GIL 時,另一個線程無法同時取得它。這並不意味著我們在這種情況下不能有多個線程。
這裡我們正在考慮Python參考實作。 CPython 是 Python 的標準實現,用作該語言行為方式的參考。還有其他實現,例如 Jython 或 IronPython。 GIL 存在於 CPython 中,直到最近我們才收到 PEP(Python 增強提案)建議將 GIL 設為可選。
GIL 的想法是防止競爭條件,當多個執行緒需要同時引用一個 Python 物件時,就會出現這種情況。如果多個執行緒修改共享變量,則該變數可能會處於意外狀態。圖片取自 Matthew Fowler 的書:
在上圖中,兩個執行緒試圖同時增加引用計數,由於兩個執行緒都增加了 1,所以最終結果給出了 1(每個執行緒是一列),而不是計數給出 2。
當處理多個任務時,就會發生計算競爭,而不必完全同時執行這兩個任務。 Rob Pyke 關於這個主題的著名短語:
競爭意味著同時處理很多事情。並行性是同時做很多事情。
想像一下這個假設的情況:如果你要做兩個蛋糕,你可以先預熱烤箱,同時準備第一個蛋糕的麵團。一旦烤箱達到正確的溫度,您就可以將第一個蛋糕的麵團放入烤箱,在等待蛋糕在烤箱中發酵的同時,您可以準備第二個蛋糕的麵團。競爭的想法基本上就是這樣,你不需要閒著、卡住、停止,在等待任務完成的時候,你可以做一個切換,改變任務。
在這種情況下,我們有兩種類型的多工:
下圖有助於總結 Python 中的並發性:
並行意味著多個任務同時執行。換句話說,並行意味著並發(處理多個任務),但並發並不意味著並行(任務不一定同時並行執行)。為了讓並行性成為可能,我們需要多個 CPU 核心。
在 Python 中,並行性是透過多處理函式庫實現的,其中我們將擁有多個 Python 進程,每個進程都有自己的 GIL。此圖有助於說明 Python 中的並行性:
在 Python 中實現並發和並行有不同的方法,我們可以使用一些函式庫來最佳化我們的程式碼,這取決於我們正在處理的操作類型,I/O 限製或 CPU 限制。 asyncio 是一個使用 async 和await 實作並發的函式庫。來自文件:
Asyncio 被用作多個非同步 Python 框架的基礎,這些框架提供高效能網路和 Web 伺服器、資料庫連接庫、分散式作業佇列等。
正如你想像的那樣,這個函式庫適合優化 I/O 密集型任務,其中有網路等待時間、寫入磁碟等。在 CPU 密集型操作中,沒有等待,我們只依賴 CPU 運算速度。
Python 的執行緒庫允許我們操作多個執行緒,但是,我們仍然處理一個CPU 核心和一個Python 進程,請記住,這是作業系統執行搶佔式多工處理的一種情況我們的任務切換。該程式庫對於優化 I/O 綁定操作也更有用。
關於線程,Real Python 網站提供了一些要點:
由於作業系統控制一個任務何時停止以及另一個任務何時啟動,因此執行緒之間共享的任何資料都需要受到保護,或執行緒安全。不幸的是 requests.Session() 不是線程安全。有多種策略可以使資料存取線程安全,具體取決於資料是什麼以及您如何使用它。其中之一是使用線程安全資料結構作為Python隊列模組的Queue。
我們在這裡找到了隊列文件。
關於Python文件中的多處理庫:
multiprocessing 是一個支援使用類似 threading 模組的 API 產生程序的套件。多處理包提供本地和遠端並發,透過使用子進程而不是執行緒有效地繞過 GIL。這就是為什麼多處理模組允許程式設計師利用一台機器上的多個處理器。
值得指出的是,在不同的CPU核心上執行多個進程並不意味著停用GIL,而是每個進程都會有自己的GIL。透過利用多個 CPU 核心,在多個可用核心之間分擔繁重的 CPU 工作負載,該程式庫更適合 CPU 限制。
來源:
福勒,馬修。 Python 與 asyncio 的並發。曼寧出版社,2022 年。
馬查多,法蘭西斯‧貝倫熱;瑪雅,路易斯‧保羅。作業系統架構:包括 SOSIM 模擬器練習和 ENADE 問題。裡約熱內盧:LTC,2013。
維基百科的線程(計算)
透過真正的 Python 並發來加速你的 Python 程式
以上是Python 中的並行與平行的詳細內容。更多資訊請關注PHP中文網其他相關文章!