【💊 Python的解憂錦囊】如何在multithread/multiprocess傳遞固定參數?

更新於 發佈於 閱讀時間約 11 分鐘
raw-image


撰寫Python的朋友都知道multithread/multiprocess能為我們帶來效能的改進,減少硬體資源的閒置,但在撰寫的過程中常常會發現到我們所設計的工作池模式會需要將「待辦清單」的工作項目當成參數傳遞進去執行, 除了「待辦清單」之外, 其餘的參數基本上都是固定的, 基於這樣的需求之下, 我們要怎麼完成呢? 讓我們耐心的看完這個篇章。

我們通常會這樣做…

假設我們設計了一個工作但尚未實作工作詳細內容, 僅印出工作資訊如下 :

def job(name: str, action: str, item: str):
"""工作內容

Args :
name (str): 什麼樣的工作
action (str): 工作的行為(加工、蓋房、...)
item: 工作的項目
Retruns:
None
"""
result = f'{name} 正在 {action} {item}'
return result

接著我們在主程序設計好我們要執行「什麼樣的工作」、「工作的行為」, 接著我們會有許多的「待辦事項」需要執行, 接著招聘好工人(num_workers)之後就可以根據作業區擴展廠區(pool),每個作業區獨立運作這些待辦清單, 那我們可能會這樣撰寫程式:


import concurrent.futures

if __name__ == "__main__":
# 設計今天的主題
name = '食品加工廠'
action = '製作'

# 待辦事項
todo_list = ['熱狗', '炸雞', '薯條', '肉乾']

num_workers = 3

# 創建一個多進程池,根據上述的工人數量擴展工作池
with concurrent.futures.ProcessPoolExecutor(max_workers=num_workers) as executor:

# 我們將大量的待辦事項轉換成每個worker需要執行的
params = [(name, action, item) for item in todo_list]
results = executor.map(job, params)

# 印出執行結果
for result in results:
print(result)
raw-image


但上述的作法真的好嗎?

我們的params不會隨著「待辦清單」越多(上千萬個事項), 導致記憶體爆掉嗎? 不妨來看看我們更改後的範例, 假設有1000萬的「待辦清單」時會發生什麼狀況? 我們也順便埋入執行的估測時間來實際看看結果。

import multiprocessing
import time
import random
import sys

def job(name: str, action: str, item: str):
"""工作內容

Args :
name (str): 工作名稱
action (str): 動作
item: 工作的項目
Retruns:
None
"""
secs = random.random()
result = f'{name} 正在 {action} {item} 花費了 {secs} 秒'
time.sleep(secs)
return result

if __name__ == "__main__":
# 固定的參數
name = '食品加工廠'
action = '製作'

# 主程序提供的待辦事項清單
# todo_list = ['熱狗', '炸雞', '薯條', '肉乾']
todo_list = [f"工作{i}" for i in range(1, 10000000)]

num_workers = 3

# 創建一個多進程池,這裡使用3個進程
with multiprocessing.Pool(processes=num_workers) as pool:
start_time = time.time()
params = [(name, action, item) for item in todo_list]
end_time = time.time()

use_bytes = sys.getsizeof(params)
use_mb = use_bytes / 1048576
print(f'渲染參數花費的時間: {end_time - start_time} 秒, 耗用的記憶體: {use_mb} MB')

results = pool.starmap(job, params)
for result in results:
print(result)

我們會發現以下光是簡單的參數就花費如此之多的記憶體耗用量, 那面對大數據時怎麼辦?

raw-image

因此我們可以這樣做…

我們在「【Python 軍火庫🧨 - functools】使用partial來設計函數樣板」有介紹到「functools.partial」這個工具庫, 我們可以利用partial的技巧製造出固定參數的新函式, 以不變應萬變,套用到multiprocess之前就不需要一堆複製的資源耗費…。

那在進入主題之前, 我們先來複習一下關於functools.partial函式, 他可以幫我們製作出固定參數的樣版。

raw-image


但聰明的大家有沒有觀察到一個狀況, 那就是動態的參數通常在前面(a, b), 而固定的參數放在後段(c), 因此底下我們的job的參數設計勢必要改一改, 由於我們的item會隨著todolist而變化, 因此需要將函式參數順序稍微修改一下成「job(item: str, name: str, action: str)」。

另外在於multiprocess的部份, 我們原先使用的是「starmap」接受多參數的模式, 但經上述演示之後覺得對於大數據的處理不太妥當, 因此我們可以更換成「map(func, iterable[, chunksize])」, 他們的差異主要在於

import multiprocessing
import time
import random
import sys
from functools import partial

def job(item: str, name: str, action: str):
"""工作內容

Args :
item (str): 工作的項目 [可變]
name (str): 工作名稱 [固定]
action (str): 動作 [固定]

Retruns:
None
"""
secs = random.random()
result = f'{name} 正在 {action} {item} 花費了 {secs} 秒'
return result

if __name__ == "__main__":
# 固定的參數
name = '食品加工廠'
action = '製作'

# 主程序提供的待辦事項清單
# todo_list = ['熱狗', '炸雞', '薯條', '肉乾']
todo_list = [f"工作{i}" for i in range(1, 10000000)]

num_workers = 24

# 創建一個多進程池,這裡使用3個進程
with multiprocessing.Pool(processes=num_workers) as pool:
start_time = time.time()
job_func = partial(job, name=name, action=action)
end_time = time.time()

use_bytes = sys.getsizeof(job_func)
use_mb = use_bytes / 1048576
print(f'渲染參數花費的時間: {end_time - start_time} 秒, 耗用的記憶體: {use_mb} MB')

results = pool.map(job_func, todo_list)
for result in results:
print(result)
raw-image

乍看之下是不是會誤以為花費更久的時間了呢? 請仔細看一下它的數字是否怪怪的, 有負數的出現…, 這是科學記號, 代表是一個非常小的數字, 也就是幾乎沒有耗損的過程, 這面對於大數據的處理, 相對能夠帶來極大的效能增幅。

結語

上述的例子仍有一些缺陷, 雖然實際上仍是以multiprocess的方式並行處理我們的運算, 但必須等待全部的工作完成後, 才回到主線程, 這對於我們跟蹤程式進度的應用會稍微不利, 不過沒關係, 我們後續也會針對這個部份進行重點分享, 歡迎持續追蹤, 讓我們一起探究軟體開發的大小事。

學習軟體開發的路上常常苦於網路資訊爆炸嗎? 教學何其多,但卻遇到無法明確選擇的困境呢? 歡迎加入「🔒 阿Han的軟體心法實戰營」, 這裡不給您冗餘的雜訊, 單刀直入直接送您業界開發重點, 避開選擇障礙的困境, 讓您獲得業界標準的開發起手式, 成為Top 1的頂尖人才。

留言
avatar-img
留言分享你的想法!
avatar-img
阿Han的沙龍
130會員
288內容數
哈囉,我是阿Han,是一位 👩‍💻 軟體研發工程師,喜歡閱讀、學習、撰寫文章及教學,擅長以圖代文,化繁為簡,除了幫助自己釐清思路之外,也希望藉由圖解的方式幫助大家共同學習,甚至手把手帶您設計出高品質的軟體產品。
阿Han的沙龍的其他內容
2025/01/29
🤔 簡單且靜態就足夠了? 相信我們在開發Python應用程式的過程中, 常常會借用Enum來定義我們可能的選項, 就像顏色紅、綠、黃會有這樣的結構: class Color(str, Enum): RED = 'red' GREED = 'green' YELLOW = 'yel
Thumbnail
2025/01/29
🤔 簡單且靜態就足夠了? 相信我們在開發Python應用程式的過程中, 常常會借用Enum來定義我們可能的選項, 就像顏色紅、綠、黃會有這樣的結構: class Color(str, Enum): RED = 'red' GREED = 'green' YELLOW = 'yel
Thumbnail
2025/01/08
當我們的系統發展到一定程度時, 難免會面臨到正式上線的問題, 要如何讓維運更加簡易呢? 尤其隨著複雜的客製化配置的出現時, 我們應該如何有效的管理, 甚至驗證配置是否如預期資料型態、格式…, 而正好 pydantic 可以滿足這樣的需求, 就讓我們來看看怎麼使用吧! 需安裝的套件 pip i
Thumbnail
2025/01/08
當我們的系統發展到一定程度時, 難免會面臨到正式上線的問題, 要如何讓維運更加簡易呢? 尤其隨著複雜的客製化配置的出現時, 我們應該如何有效的管理, 甚至驗證配置是否如預期資料型態、格式…, 而正好 pydantic 可以滿足這樣的需求, 就讓我們來看看怎麼使用吧! 需安裝的套件 pip i
Thumbnail
2025/01/02
要如何使用unicorn啟動多個FastAPI服務, 歡迎參考我們的「【💊 Python的解憂錦囊 - FastAPI】如何啟動多個Workers」。 當我們試著設計帶入模組化時… 我們在「【💊 Python的解憂錦囊 - FastAPI】使用 lifespan 來共享資料與管理生命週期
Thumbnail
2025/01/02
要如何使用unicorn啟動多個FastAPI服務, 歡迎參考我們的「【💊 Python的解憂錦囊 - FastAPI】如何啟動多個Workers」。 當我們試著設計帶入模組化時… 我們在「【💊 Python的解憂錦囊 - FastAPI】使用 lifespan 來共享資料與管理生命週期
Thumbnail
看更多
你可能也想看
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
全球科技產業的焦點,AKA 全村的希望 NVIDIA,於五月底正式發布了他們在今年 2025 第一季的財報 (輝達內部財務年度為 2026 Q1,實際日曆期間為今年二到四月),交出了打敗了市場預期的成績單。然而,在銷售持續高速成長的同時,川普政府加大對於中國的晶片管制......
Thumbnail
全球科技產業的焦點,AKA 全村的希望 NVIDIA,於五月底正式發布了他們在今年 2025 第一季的財報 (輝達內部財務年度為 2026 Q1,實際日曆期間為今年二到四月),交出了打敗了市場預期的成績單。然而,在銷售持續高速成長的同時,川普政府加大對於中國的晶片管制......
Thumbnail
重點摘要: 6 月繼續維持基準利率不變,強調維持高利率主因為關稅 點陣圖表現略為鷹派,收斂 2026、2027 年降息預期 SEP 連續 2 季下修 GDP、上修通膨預測值 --- 1.繼續維持利率不變,強調需要維持高利率是因為關稅: 聯準會 (Fed) 召開 6 月利率會議
Thumbnail
重點摘要: 6 月繼續維持基準利率不變,強調維持高利率主因為關稅 點陣圖表現略為鷹派,收斂 2026、2027 年降息預期 SEP 連續 2 季下修 GDP、上修通膨預測值 --- 1.繼續維持利率不變,強調需要維持高利率是因為關稅: 聯準會 (Fed) 召開 6 月利率會議
Thumbnail
在Python中,queue是一個非常有用的模块。 它提供了多種佇列(queue)實現,用於在多線程環境中安全地交換信息或者數據。 佇列(queue)是一種先進先出(FIFO)的數據結構,允許在佇列的一端插入元素,另一端取出元素。(FIFO 是First In, First Out 的縮寫)
Thumbnail
在Python中,queue是一個非常有用的模块。 它提供了多種佇列(queue)實現,用於在多線程環境中安全地交換信息或者數據。 佇列(queue)是一種先進先出(FIFO)的數據結構,允許在佇列的一端插入元素,另一端取出元素。(FIFO 是First In, First Out 的縮寫)
Thumbnail
當你需要在 Python 中執行多個任務,但又不希望它們相互阻塞時,可以使用 threading 模組。 threading 模組允許你在單個程序中創建多個執行緒,這些執行緒可以同時運行,從而實現並行執行多個任務的效果。
Thumbnail
當你需要在 Python 中執行多個任務,但又不希望它們相互阻塞時,可以使用 threading 模組。 threading 模組允許你在單個程序中創建多個執行緒,這些執行緒可以同時運行,從而實現並行執行多個任務的效果。
Thumbnail
關於多執行緒/多行程的使用方式 在Python 3.2版本之後加入了「concurrent.futures」啟動平行任務, 它可以更好的讓我們管理多執行緒/多行程的應用場景,讓我們在面對這種併發問題時可以不必害怕, 用一個非常簡單的方式就能夠處裡, 底下我們將為您展示一段程式碼: imp
Thumbnail
關於多執行緒/多行程的使用方式 在Python 3.2版本之後加入了「concurrent.futures」啟動平行任務, 它可以更好的讓我們管理多執行緒/多行程的應用場景,讓我們在面對這種併發問題時可以不必害怕, 用一個非常簡單的方式就能夠處裡, 底下我們將為您展示一段程式碼: imp
Thumbnail
撰寫Python的朋友都知道multithread/multiprocess能為我們帶來效能的改進,減少硬體資源的閒置,但在撰寫的過程中常常會發現到我們所設計的工作池模式會需要將「待辦清單」的工作項目當成參數傳遞進去執行, 除了「待辦清單」之外, 其餘的參數基本上都是固定的, 基於這樣的需求之下
Thumbnail
撰寫Python的朋友都知道multithread/multiprocess能為我們帶來效能的改進,減少硬體資源的閒置,但在撰寫的過程中常常會發現到我們所設計的工作池模式會需要將「待辦清單」的工作項目當成參數傳遞進去執行, 除了「待辦清單」之外, 其餘的參數基本上都是固定的, 基於這樣的需求之下
Thumbnail
  在說執行緒(Thread)時就要先知道什麼是程式(Program)、程序(Process),才能了解什麼是執行緒(Thread),因為它們間都有著神秘的關係與關聯,再更深入一點就又會有多程序(muti-Process)、多執行緒(muti-Thread),我們就先一一說明好了,了解它們後再使用時
Thumbnail
  在說執行緒(Thread)時就要先知道什麼是程式(Program)、程序(Process),才能了解什麼是執行緒(Thread),因為它們間都有著神秘的關係與關聯,再更深入一點就又會有多程序(muti-Process)、多執行緒(muti-Thread),我們就先一一說明好了,了解它們後再使用時
Thumbnail
When I was doing the development of the company’s data dashboard, I often pulled tables from various databases for calculation.
Thumbnail
When I was doing the development of the company’s data dashboard, I often pulled tables from various databases for calculation.
Thumbnail
介紹 📷 定義 處理序(Process) (大陸:進程): 一個程序運行時,占用全部計算資源的總和 執行緒(Thread) (大陸:線程):是作業系統能夠進行運算排程的最小單位。 大部分情況下,它被包含在行程之中,是行程中的實際運作單位。 C#多線程和異步(一)——基本概念和使用方法 執行緒帶來的
Thumbnail
介紹 📷 定義 處理序(Process) (大陸:進程): 一個程序運行時,占用全部計算資源的總和 執行緒(Thread) (大陸:線程):是作業系統能夠進行運算排程的最小單位。 大部分情況下,它被包含在行程之中,是行程中的實際運作單位。 C#多線程和異步(一)——基本概念和使用方法 執行緒帶來的
Thumbnail
行程(進程、process)、執行緒(線程、thread)、上下文切換(context switch)、行程控制塊(PCB)、行程排班(process scheduler)、行程狀態、執行緒模式
Thumbnail
行程(進程、process)、執行緒(線程、thread)、上下文切換(context switch)、行程控制塊(PCB)、行程排班(process scheduler)、行程狀態、執行緒模式
Thumbnail
今天來到Day5了,也來到基礎教學的最後一部分,今天要講解的就是函式(function),有分成內建函數,以及自訂函數,再來是import模組,也就是導入py檔,除了可以導入自行撰寫的py檔,網路上也有許多大神分享相當方便使用的py檔,最後再講解一下如何進行異常處理,也就是Debug的部分
Thumbnail
今天來到Day5了,也來到基礎教學的最後一部分,今天要講解的就是函式(function),有分成內建函數,以及自訂函數,再來是import模組,也就是導入py檔,除了可以導入自行撰寫的py檔,網路上也有許多大神分享相當方便使用的py檔,最後再講解一下如何進行異常處理,也就是Debug的部分
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News