Python中的並行處理


介紹

在當今快節奏的數字環境中,有效完成計算密集型任務對於開發人員和資料科學家至關重要。幸運的是,Python 憑藉其適應性和廣泛的生態系統,提供了強大的並行處理能力。透過將複雜問題分解成更小、更易於管理的任務,這些任務可以併發執行,我們可以獲得巨大的效能提升。

Python 的並行處理功能使我們能夠透過利用可用的計算資源,更快速、更有效地處理諸如網路抓取、科學模擬和資料分析等任務。在這篇文章中,我們將踏上 Python 並行處理之旅。我們將探索多種方法,包括多程序、非同步程式設計和多執行緒,並學習如何有效地利用它們來克服系統中的效能瓶頸。加入我們,一起釋放 Python 並行處理的全部潛能,並達到效能和生產力的新高度。

瞭解並行處理

並行處理是指將一項任務分解成較小的子任務,並在多個處理器或核心上併發執行這些子任務。透過有效利用可用的計算資源,並行處理可以顯著減少程式的總執行時間。Python 提供了多種並行處理方法,包括非同步程式設計、多程序和多執行緒。

Python 中的多執行緒

多執行緒方法利用單個程序內的多個執行緒併發執行,同時共享相同的記憶體。Python 的 threading 模組可以輕鬆實現多執行緒。然而,由於全域性直譯器鎖 (GIL),Python 中的多執行緒對於 CPU 密集型操作可能不會帶來明顯的加速,因為 GIL 每次只允許一個執行緒執行 Python 位元組碼。但是,多執行緒對於 I/O 密集型任務很有用,因為它允許執行緒在等待 I/O 操作完成時執行其他操作。

讓我們來看一個使用多執行緒下載多個網頁的示例

示例

import threading import requests 
 
def download_page(url): 
    response = requests.get(url)    
print(f"Downloaded {url}") 
 
urls = [ 
    "https://example.com", 
    "https://google.com", 
    "https://openai.com" 
] 
 
threads = [] 
 for url in 
 urls: 
    thread = threading.Thread(target=download_page,
args=(url,))     thread.start()    threads.append(thread) 
 
for thread in threads: 
    thread.join() 

輸出

Downloaded https://example.com 
Downloaded https://google.com 
Downloaded https://openai.com 

上面的程式碼片段透過在自己的執行緒中下載每個 URL,實現了多個下載的併發執行。join() 函式確保主執行緒在每個執行緒完成之前等待。

Python 中的多程序

與多執行緒不同,多程序透過使用多個程序(每個程序都有自己的記憶體空間)來提供真正的並行性。Python 的 multiprocessing 模組提供了一個用於實現多程序的高階介面。多程序適用於 CPU 密集型任務,因為每個程序都在一個單獨的 Python 直譯器中執行,從而避免了 GIL 對多執行緒的限制。

下面的程式碼使用了多程序。一旦 pool 類建立了一個工作程序池,map() 方法就會將任務分配到可用的程序中。results 列表是結果的集合。

考慮下面的示例,我們使用多程序對列表中的每個整數進行平方運算

示例

import multiprocessing 
 
def square(number):    
return number ** 2 
 
numbers = [1, 2, 3, 4, 5] 
 
with multiprocessing.Pool() as pool: 
    results = pool.map(square, numbers) 
 
print(results) 

輸出

[1, 4, 9, 16, 25] 

Python 中的非同步程式設計

透過利用非阻塞操作,非同步程式設計可以有效地執行 I/O 密集型任務。藉助 asyncio 包,可以使用協程、事件迴圈和期貨來建立 Python 中的非同步程式碼。隨著網路應用程式和 API 的日益普及,非同步程式設計變得越來越重要。

下面的程式碼示例中,fetch_page() 協程使用 aiohttp 非同步獲取網頁。main() 方法建立了一個任務列表,然後使用 asyncio.gather() 併發執行這些任務。await 關鍵字用於等待任務完成並獲取結果。

讓我們來看一個使用 asyncio 和 aiohttp 非同步獲取多個網頁的示例

示例

import asyncio 
import aiohttp 
 
async def fetch_page(url):     async with aiohttp.ClientSession() as session:         async with session.get(url) as response: 
            return await response.text() 
 
async def main(): 
    urls = [ 
        "https://example.com", 
        "https://google.com", 
        "https://openai.com" 
    ] 
 
    tasks = [fetch_page(url) for url in urls]     pages = await asyncio.gather(*tasks)     
print(pages) 
 
asyncio.run(main()) 

輸出

['<!doctype html>\n<html>\n<head>\n    <title>Example Domain</title>\n\n    <meta 
charset="utf-8" />\n    <meta http-equiv="Content-type"content="text/html; charset=utf-8" />\n    <meta name="viewport" content="width=device-width, initialscale=1" />\n    <style type="text/css">\n    body {\n        background-color: #f0f0f2;\n  margin: 0;\n        padding: 0;\n        font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;\n        \n    }\n    div {\n        width: 600px;\n        margin: 5em auto;\n  padding: 50px;\n        background-color: #fff;\n        border-radius: 1em;\n    }\n    a:link, a:visited {\n        color: #38488f;\n        text-decoration: none;\n    }\n    @media (maxwidth: 700px) {\n        body {\n            background-color: #fff;\n        }\n        div {\n  width: auto;\n            margin: 0 auto;\n            border-radius: 0;\n            padding: 1em;\n        }\n    }\n    </style>    \n</head>\n\n<body>\n<div>\n    <h1>Example Domain</h1>\n    <p>This domain is for use in illustrative examples in documents. You may use this\n    domain in literature without prior coordination or asking for permission.</p>\n    <p><a href="https://www.iana.org/domains/example">More information...</a></p>\n</div>\n</body>\n</html>', '<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en"><head><meta content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for." name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/logos/doodles/2021/mom-
and-dad-6116550989716480.2-law.gif" itemprop="image"><link href="/logos/doodles/2021/mom-and-dad-6116550989716480.2-law.gif" rel="icon" type="image/gif"><title>Google</title><script nonce="sJwM0Ptp5a/whzxPtTD8Yw==">(function(){window.google={kEI:'cmKgYY37A7 K09QPhzKuACw',kEXPI:'1354557,1354612,1354620,1354954,1355090,1355493,13556
83,3700267,4029815,4031109,4032677,4036527,4038022,4043492,4045841,4048347,4
048490,4052469,4055589,4056520,4057177,4057696,4060329,4060798,4061854,4062 531,4064696,406 '

選擇正確的方法

Python 的並行處理技術根據手頭任務的具體情況而有所不同。以下是一些指導原則,可幫助您做出明智的決策

對於 I/O 密集型任務,其中大部分執行時間都花費在等待輸入/輸出操作上,多執行緒是合適的。它非常適合諸如下載檔案、使用 API 和操作檔案等任務。由於 Python 的全域性直譯器鎖 (GIL),多執行緒可能不會顯著加速 CPU 密集型任務。

另一方面,多程序非常適合涉及密集計算的 CPU 密集型任務。它透過利用多個程序(每個程序都有自己的記憶體空間)來實現真正的並行性,並繞過了 GIL 的限制。但是,它在記憶體消耗和程序間通訊方面會產生額外的開銷。

對於涉及網路操作的 I/O 密集型任務,使用 asyncio 等庫執行的非同步程式設計很有用。它利用非阻塞 I/O 操作,以便任務可以繼續進行,而無需等待每個操作完成。此方法有效地管理多個併發連線,使其適用於網路伺服器開發、Web API 互動和網路抓取。非同步程式設計最大程度地減少了 I/O 操作的等待時間,確保響應能力和可擴充套件性。

結論

Python 的並行處理能力提供了機會來提高需要複雜計算的任務的效率。無論您選擇使用多執行緒、多程序還是非同步程式設計,Python 都提供了必要的工具和模組來有效地利用併發性。透過理解您的任務的性質並選擇合適的方法,您可以最大限度地利用並行處理的優勢並縮短執行時間。因此,請大膽探索,充分利用 Python 的並行性來建立更快、更高效的應用程式。

更新於:2023-07-25

5K+ 閱讀量

開啟你的 職業生涯

透過完成課程獲得認證

開始學習
廣告

© . All rights reserved.