目錄
引言
Executor和Future
使用submit來操作線程池/進程池
map/wait來操作執行緒池/進程池" >使用map/wait來操作執行緒池/進程池
使用submit操作回顧
使用map
第三種選擇wait
首頁 後端開發 Python教學 Python並發編程之線程池/進程池的詳細介紹

Python並發編程之線程池/進程池的詳細介紹

Mar 17, 2017 pm 05:38 PM
python

引言

Python標準函式庫為我們提供了threading和multiprocessing模組編寫對應的多執行緒/多進程程式碼,但是當專案達到一定的規模,頻繁創建/銷毀進程或執行緒是非常消耗資源的,這個時候我們就要編寫自己的執行緒池/進程池,以空間換時間。但從Python3.2開始,標準函式庫為我們提供了concurrent.futures模組,它提供了ThreadPoolExecutor和ProcessPoolExecutor兩個類,實現了對threading和multiprocessing的進一步抽象,對編寫線程池/進程池提供了直接的支援。

Executor和Future

concurrent.futures模組的基礎是Exectuor,Executor是一個抽象類別,它不能直接使用。但是它提供的兩個子類別ThreadPoolExecutor和ProcessPoolExecutor卻非常有用,顧名思義兩者分別被用來建立執行緒池和進程池的程式碼。我們可以將對應的tasks直接放入線程池/進程池,不需要維護Queue來操心死鎖的問題,線程池/進程池會自動幫我們調度。

Future這個概念相信有java和nodejs程式經驗的朋友肯定不陌生了,你可以把它理解為一個在未來完成的操作,這是非同步程式設計的基礎,傳統程式模式下例如我們操作queue.get的時候,在等待返回結果之前會產生阻塞,cpu不能讓出來做其他事情,而Future的引入幫助我們在等待的這段時間可以完成其他的操作。關於在Python中進行非同步IO可以閱讀完本文之後參考我的Python並發程式設計協程/非同步IO。

p.s: 如果你還是在堅守Python2.x,請先安裝futures模組。

pip install futures
登入後複製

使用submit來操作線程池/進程池

我們先透過下面這段程式碼來了解線程池的概念

# example1.py
from concurrent.futures import ThreadPoolExecutor
import time
def return_future_result(message):
    time.sleep(2)
    return message
pool = ThreadPoolExecutor(max_workers=2)  # 创建一个最大可容纳2个task的线程池
future1 = pool.submit(return_future_result, ("hello"))  # 往线程池里面加入一个task
future2 = pool.submit(return_future_result, ("world"))  # 往线程池里面加入一个task
print(future1.done())  # 判断task1是否结束
time.sleep(3)
print(future2.done())  # 判断task2是否结束
print(future1.result())  # 查看task1返回的结果
print(future2.result())  # 查看task2返回的结果
登入後複製

我們根據運行結果來分析一下。我們使用submit方法來在執行緒池中加入一個task,submit傳回一個Future物件,對於Future物件可以簡單地理解為一個在未來完成的操作。在第一個print語句中很明顯因為time.sleep(2)的原因我們的future1沒有完成,因為我們使用time.sleep(3)暫停了主線程,所以到第二個print語句的時候我們線程池裡的任務都已經全部結束。

ziwenxie :: ~ » python example1.py
False
True
hello
world
# 在上述程序执行的过程中,通过ps命令我们可以看到三个线程同时在后台运行
ziwenxie :: ~ » ps -eLf | grep python
ziwenxie      8361  7557  8361  3    3 19:45 pts/0    00:00:00 python example1.py
ziwenxie      8361  7557  8362  0    3 19:45 pts/0    00:00:00 python example1.py
ziwenxie      8361  7557  8363  0    3 19:45 pts/0    00:00:00 python example1.py
登入後複製

上面的程式碼我們也可以改寫為進程池形式,api和執行緒池如出一轍,我就不囉嗦了。

# example2.py
from concurrent.futures import ProcessPoolExecutor
import time
def return_future_result(message):
    time.sleep(2)
    return message
pool = ProcessPoolExecutor(max_workers=2)
future1 = pool.submit(return_future_result, ("hello"))
future2 = pool.submit(return_future_result, ("world"))
print(future1.done())
time.sleep(3)
print(future2.done())
print(future1.result())
print(future2.result())
登入後複製

下面是運行結果

ziwenxie :: ~ » python example2.py
False
True
hello
world
ziwenxie :: ~ » ps -eLf | grep python
ziwenxie      8560  7557  8560  3    3 19:53 pts/0    00:00:00 python example2.py
ziwenxie      8560  7557  8563  0    3 19:53 pts/0    00:00:00 python example2.py
ziwenxie      8560  7557  8564  0    3 19:53 pts/0    00:00:00 python example2.py
ziwenxie      8561  8560  8561  0    1 19:53 pts/0    00:00:00 python example2.py
ziwenxie      8562  8560  8562  0    1 19:53 pts/0    00:00:00 python example2.py
登入後複製

使用map/wait來操作執行緒池/進程池

除了submit,Exectuor也為我們提供了map方法,和內建的map用法類似,下面我們透過兩個例子來比較兩者的差異。

使用submit操作回顧

# example3.py
import concurrent.futures
import urllib.request
URLS = ['http://httpbin.org', 'http://example.com/', 'https://api.github.com/']
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))
登入後複製

從運行結果可以看出,as_completed不是按照URLS列表元素的順序傳回的

ziwenxie :: ~ » python example3.py
'http://example.com/' page is 1270 byte
'https://api.github.com/' page is 2039 bytes
'http://httpbin.org' page is 12150 bytes
登入後複製

使用map

# example4.py
import concurrent.futures
import urllib.request
URLS = ['http://httpbin.org', 'http://example.com/', 'https://api.github.com/']
def load_url(url):
    with urllib.request.urlopen(url, timeout=60) as conn:
        return conn.read()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    for url, data in zip(URLS, executor.map(load_url, URLS)):
        print('%r page is %d bytes' % (url, len(data)))
登入後複製

從運行結果可以看出,map是按照URLS列表元素的順序返回的,並且寫出的程式碼更加簡潔直觀,我們可以根據具體的需求任選一種。

ziwenxie :: ~ » python example4.py
'http://httpbin.org' page is 12150 bytes
'http://example.com/' page is 1270 bytes
'https://api.github.com/' page is 2039 bytes
登入後複製

第三種選擇wait

wait方法接會回傳一個tuple(元組),tuple包含兩個set(集合),一個是completed(已完成的)另外一個是uncompleted(未完成的)。使用wait方法的一個優點就是獲得更大的自由度,它接收三個參數FIRST_COMPLETED, FIRST_EXCEPTION 和ALL_COMPLETE,預設為ALL_COMPLETED。

我們透過下面這個範例來看三個參數的差異

from concurrent.futures import ThreadPoolExecutor, wait, as_completed
from time import sleep
from random import randint
def return_after_random_secs(num):
    sleep(randint(1, 5))
    return "Return of {}".format(num)
pool = ThreadPoolExecutor(5)
futures = []
for x in range(5):
    futures.append(pool.submit(return_after_random_secs, x))
print(wait(futures))
# print(wait(futures, timeout=None, return_when='FIRST_COMPLETED'))
登入後複製

如果採用預設的ALL_COMPLETED,程式會阻塞直到執行緒池裡面的所有任務都完成。

ziwenxie :: ~ » python example5.py
DoneAndNotDoneFutures(done={
<Future at 0x7f0b06c9bc88 state=finished returned str>,
<Future at 0x7f0b06cbaa90 state=finished returned str>,
<Future at 0x7f0b06373898 state=finished returned str>,
<Future at 0x7f0b06352ba8 state=finished returned str>,
<Future at 0x7f0b06373b00 state=finished returned str>}, not_done=set())
登入後複製

如果採用FIRST_COMPLETED參數,程式並不會等到執行緒池裡面所有的任務都完成。

ziwenxie :: ~ » python example5.py
DoneAndNotDoneFutures(done={
<Future at 0x7f84109edb00 state=finished returned str>,
<Future at 0x7f840e2e9320 state=finished returned str>,
<Future at 0x7f840f25ccc0 state=finished returned str>},
not_done={<Future at 0x7f840e2e9ba8 state=running>,
<Future at 0x7f840e2e9940 state=running>})
登入後複製

以上是Python並發編程之線程池/進程池的詳細介紹的詳細內容。更多資訊請關注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脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

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

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

PS一直顯示正在載入是什麼原因? PS一直顯示正在載入是什麼原因? Apr 06, 2025 pm 06:39 PM

PS“正在載入”問題是由資源訪問或處理問題引起的:硬盤讀取速度慢或有壞道:使用CrystalDiskInfo檢查硬盤健康狀況並更換有問題的硬盤。內存不足:升級內存以滿足PS對高分辨率圖片和復雜圖層處理的需求。顯卡驅動程序過時或損壞:更新驅動程序以優化PS和顯卡之間的通信。文件路徑過長或文件名有特殊字符:使用簡短的路徑和避免使用特殊字符。 PS自身問題:重新安裝或修復PS安裝程序。

如何加快PS的載入速度? 如何加快PS的載入速度? Apr 06, 2025 pm 06:27 PM

解決 Photoshop 啟動慢的問題需要多管齊下,包括:升級硬件(內存、固態硬盤、CPU);卸載過時或不兼容的插件;定期清理系統垃圾和過多的後台程序;謹慎關閉無關緊要的程序;啟動時避免打開大量文件。

PS啟動時一直顯示正在載入如何解決? PS啟動時一直顯示正在載入如何解決? Apr 06, 2025 pm 06:36 PM

PS啟動時卡在“正在載入”可能是由於各種原因造成的:禁用損壞或衝突的插件。刪除或重命名損壞的配置文件。關閉不必要的程序或升級內存,避免內存不足。升級到固態硬盤,加快硬盤讀取速度。重裝PS修復損壞的系統文件或安裝包問題。查看錯誤日誌分析啟動過程中的錯誤信息。

PS打開文件時一直顯示正在載入如何解決? PS打開文件時一直顯示正在載入如何解決? Apr 06, 2025 pm 06:33 PM

PS打開文件時出現“正在載入”卡頓,原因可能包括:文件過大或損壞、內存不足、硬盤速度慢、顯卡驅動問題、PS版本或插件衝突。解決方法依次為:檢查文件大小和完整性、增加內存、升級硬盤、更新顯卡驅動、卸載或禁用可疑插件、重裝PS。通過逐步排查,並善用PS的性能設置,養成良好的文件管理習慣,可以有效解決該問題。

html下一頁功能 html下一頁功能 Apr 06, 2025 am 11:45 AM

<p>可以通過 HTML 創建下一頁功能,步驟包括:創建容器元素、分割內容、添加導航鏈接、隱藏其他頁面、添加腳本。該功能允許用戶瀏覽分段的內容,每次只顯示一頁,適用於展示大量數據或內容。 </p>

PS載入慢與電腦配置有關嗎? PS載入慢與電腦配置有關嗎? Apr 06, 2025 pm 06:24 PM

PS載入慢的原因在於硬件(CPU、內存、硬盤、顯卡)和軟件(系統、後台程序)的綜合影響。解決方法包括:升級硬件(尤其是更換固態硬盤),優化軟件(清理系統垃圾、更新驅動、檢查PS設置),處理PS文件。定期維護電腦也有助於提升PS運行速度。

PS執行操作時一直顯示正在載入如何解決? PS執行操作時一直顯示正在載入如何解決? Apr 06, 2025 pm 06:30 PM

PS卡在“正在載入”?解決方法包括:檢查電腦配置(內存、硬盤、處理器)、清理硬盤碎片、更新顯卡驅動、調整PS設置、重新安裝PS,以及養成良好的編程習慣。

PS導出PDF可以批量導出嗎 PS導出PDF可以批量導出嗎 Apr 06, 2025 pm 04:54 PM

PS批量導出PDF的方法有三種:利用PS動作功能:錄製打開文件和導出PDF動作,循環執行動作即可。借助第三方軟件:使用文件管理軟件或自動化工具指定輸入輸出文件夾,設置文件名格式即可。使用腳本:編寫腳本定制批量導出邏輯,但需要編程知識。

See all articles