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

更新於 2024/10/24閱讀時間約 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
116會員
261內容數
哈囉,我是阿Han,是一位 👩‍💻 軟體研發工程師,喜歡閱讀、學習、撰寫文章及教學,擅長以圖代文,化繁為簡,除了幫助自己釐清思路之外,也希望藉由圖解的方式幫助大家共同學習,甚至手把手帶您設計出高品質的軟體產品。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
阿Han的沙龍 的其他內容
我們在「【💊 Python的解憂錦囊】如何將dict轉成json並儲存」有介紹過如何將dict型態的資料轉換成json,除了json之外, 另一個耳熟能詳的資料交換格式就是csv了, 我們常常會將csv讀進來, 並使用預先設計的@dataclass來存放, 如此一來實際運行時, 更能夠貼近於我
關於json的資料交換格式請參考「【程式語言 - Javascript】輕量資料格式 JSON」, 我們常常會在使用套件的過程中發現回傳值的型態都會有「dict」的蹤跡, 為什麼呢? 因為動態、彈性、靈活, 不需要預先定義類別來明確指定每個欄位的內容, 但缺點就是文件必須寫清楚內容物是哪些, 否
「functools.partial」是Python中的一個標準函式庫,它可以讓我們基於既有的函式封裝成多種不同用途的函式,就如同上圖所示,我們設計了一個乘法(multiply)的函數,使用了partial讓函數的參數「c」固定下來依據用途不同變化出「double」、「triple」,這樣一來我
最近正好在研究「silero-vad」這套工具, 但根據官方教學,預設的載入方式會從網路上進行下載模型的動作: model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad',
我們在「【💎Python 軍火庫 - devpi】pip install…等太久了嗎🤔? 您需要來點緩存機制」有介紹過pypi套件緩存的架設方式, 那架設好了之後, 我們在下載的部份會有一層快取及代理的前哨站, 但假如我們的套件不在pypi平台時怎麼辦呢? 就像torch的套件就必須仰賴外部的來
相信玩過Python一陣子的朋友應該曾經都遇到過套件版本衝突的問題吧…, 這實在是很惱人, 但如果我們能夠快速的檢驗我們所安裝的套件是否如我們所預期的版本, 該有多好, 如此一來能夠讓自己更加安心一些, 那麼今天將提供兩種方法讓我們來檢查一番。 列出所有套件及版本 簡單且暴力。 pip lis
我們在「【💊 Python的解憂錦囊】如何將dict轉成json並儲存」有介紹過如何將dict型態的資料轉換成json,除了json之外, 另一個耳熟能詳的資料交換格式就是csv了, 我們常常會將csv讀進來, 並使用預先設計的@dataclass來存放, 如此一來實際運行時, 更能夠貼近於我
關於json的資料交換格式請參考「【程式語言 - Javascript】輕量資料格式 JSON」, 我們常常會在使用套件的過程中發現回傳值的型態都會有「dict」的蹤跡, 為什麼呢? 因為動態、彈性、靈活, 不需要預先定義類別來明確指定每個欄位的內容, 但缺點就是文件必須寫清楚內容物是哪些, 否
「functools.partial」是Python中的一個標準函式庫,它可以讓我們基於既有的函式封裝成多種不同用途的函式,就如同上圖所示,我們設計了一個乘法(multiply)的函數,使用了partial讓函數的參數「c」固定下來依據用途不同變化出「double」、「triple」,這樣一來我
最近正好在研究「silero-vad」這套工具, 但根據官方教學,預設的載入方式會從網路上進行下載模型的動作: model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad',
我們在「【💎Python 軍火庫 - devpi】pip install…等太久了嗎🤔? 您需要來點緩存機制」有介紹過pypi套件緩存的架設方式, 那架設好了之後, 我們在下載的部份會有一層快取及代理的前哨站, 但假如我們的套件不在pypi平台時怎麼辦呢? 就像torch的套件就必須仰賴外部的來
相信玩過Python一陣子的朋友應該曾經都遇到過套件版本衝突的問題吧…, 這實在是很惱人, 但如果我們能夠快速的檢驗我們所安裝的套件是否如我們所預期的版本, 該有多好, 如此一來能夠讓自己更加安心一些, 那麼今天將提供兩種方法讓我們來檢查一番。 列出所有套件及版本 簡單且暴力。 pip lis
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
MinIO 是一個高性能的物件存儲系統,設計用於大規模的數據存儲需求, 甚至是各種非結構化數據也都能往這邊儲存, 也支持群集擴展, 非常適合正在尋找儲存方案的朋友們。 我們在「【💎 Message Queue - Kafka 案例篇】如何將檔案流上傳到minio - 完整檔案 」介紹了如
Thumbnail
訊息的即時傳遞已然成為現代社會的趨勢了, 影音也是如此, 即時! 即時! 即時! 已經是目前使用者體驗的必要元素了, 在這邊我們要分享的主題是如何在python程式語言的情境下使用ffmpeg來將音檔串流的轉換格式, 為什麼會有這樣的需求呢? 因為我們處理音檔時可能會需要統一輸出的格式, 當然背後也
Thumbnail
當我們在進行影像處理時, 在Python的世界最常聽到的就是OpenCV, 而我們在處理影片時也會想要僅針對某時間段的影片進行處理, 今天我們就來教您如何透過OpenCV來讀取特定的時間區段。 在進入主題之前, 有一些基本概念務必先行建立, 一個影片是由多張圖片組成的, 因此最小單元為一張圖
Thumbnail
關於多執行緒/多行程的使用方式 在Python 3.2版本之後加入了「concurrent.futures」啟動平行任務, 它可以更好的讓我們管理多執行緒/多行程的應用場景,讓我們在面對這種併發問題時可以不必害怕, 用一個非常簡單的方式就能夠處裡, 底下我們將為您展示一段程式碼: imp
Thumbnail
我們在「【🔒 Python 先修班】👆 打造友善的使用者互動CLI介面」有介紹Python的Click命令列參數設計介面的方式, 那我們除了設計出介面提供使用者互動之外, 有時候也需要一點驗證機制, 畢竟我們心裡都清楚「garbage in, garbage out」的後果, 為了減少這種狀
Thumbnail
我們將探索函式的定義和調用,這是程式設計中非常重要且強大的概念,它可以將大型程式切割成小的、可重複使用的函式。讓我們一起來了解吧!函式的定義、呼叫和返回值是學習函式的核心。
Thumbnail
探索Python學習筆記中列表的建立、存取和常用方法。從使用中括號定義列表到了解索引、新增、刪除、修改等操作,並介紹append、remove、count等常用方法。
Thumbnail
在本篇Python學習筆記中,我們探討了字典的建立與存取,以及常用方法,字典是一種強大的資料型態,透過key和value的對應關係存儲和取得資料,我們學會了建立字典、存取資料、新增/修改/刪除項目,以及取得key和value的方法,字典是Python中不可或缺的工具!
Thumbnail
我們探討了while迴圈的使用,不同於for迴圈,while迴圈以條件式判斷為基礎,而非限定重複次數。我們介紹了使用break語句強制結束迴圈,以及使用continue語句跳過特定程式碼並返回迴圈開頭,同時,我們提及了無窮迴圈的概念,強調了在迴圈中必須更改迴圈變數的值,以避免無窮迴圈的發生。
Thumbnail
經濟是國家的命脈,社稷重點無可厚非,國際情勢不好、經濟危機出現時,國家資源救市,穩定法人、投資人信心,維持正常的金融機轉,讓國家度過危機,👍值得嘉許,只是這次國安基金護盤的故事,讓人百般尋味。 台股去年創下18650破紀錄新高,隨著國際局勢一起回檔,國安基金決定進場護盤: 第一:當時股市萬八,不是
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
MinIO 是一個高性能的物件存儲系統,設計用於大規模的數據存儲需求, 甚至是各種非結構化數據也都能往這邊儲存, 也支持群集擴展, 非常適合正在尋找儲存方案的朋友們。 我們在「【💎 Message Queue - Kafka 案例篇】如何將檔案流上傳到minio - 完整檔案 」介紹了如
Thumbnail
訊息的即時傳遞已然成為現代社會的趨勢了, 影音也是如此, 即時! 即時! 即時! 已經是目前使用者體驗的必要元素了, 在這邊我們要分享的主題是如何在python程式語言的情境下使用ffmpeg來將音檔串流的轉換格式, 為什麼會有這樣的需求呢? 因為我們處理音檔時可能會需要統一輸出的格式, 當然背後也
Thumbnail
當我們在進行影像處理時, 在Python的世界最常聽到的就是OpenCV, 而我們在處理影片時也會想要僅針對某時間段的影片進行處理, 今天我們就來教您如何透過OpenCV來讀取特定的時間區段。 在進入主題之前, 有一些基本概念務必先行建立, 一個影片是由多張圖片組成的, 因此最小單元為一張圖
Thumbnail
關於多執行緒/多行程的使用方式 在Python 3.2版本之後加入了「concurrent.futures」啟動平行任務, 它可以更好的讓我們管理多執行緒/多行程的應用場景,讓我們在面對這種併發問題時可以不必害怕, 用一個非常簡單的方式就能夠處裡, 底下我們將為您展示一段程式碼: imp
Thumbnail
我們在「【🔒 Python 先修班】👆 打造友善的使用者互動CLI介面」有介紹Python的Click命令列參數設計介面的方式, 那我們除了設計出介面提供使用者互動之外, 有時候也需要一點驗證機制, 畢竟我們心裡都清楚「garbage in, garbage out」的後果, 為了減少這種狀
Thumbnail
我們將探索函式的定義和調用,這是程式設計中非常重要且強大的概念,它可以將大型程式切割成小的、可重複使用的函式。讓我們一起來了解吧!函式的定義、呼叫和返回值是學習函式的核心。
Thumbnail
探索Python學習筆記中列表的建立、存取和常用方法。從使用中括號定義列表到了解索引、新增、刪除、修改等操作,並介紹append、remove、count等常用方法。
Thumbnail
在本篇Python學習筆記中,我們探討了字典的建立與存取,以及常用方法,字典是一種強大的資料型態,透過key和value的對應關係存儲和取得資料,我們學會了建立字典、存取資料、新增/修改/刪除項目,以及取得key和value的方法,字典是Python中不可或缺的工具!
Thumbnail
我們探討了while迴圈的使用,不同於for迴圈,while迴圈以條件式判斷為基礎,而非限定重複次數。我們介紹了使用break語句強制結束迴圈,以及使用continue語句跳過特定程式碼並返回迴圈開頭,同時,我們提及了無窮迴圈的概念,強調了在迴圈中必須更改迴圈變數的值,以避免無窮迴圈的發生。
Thumbnail
經濟是國家的命脈,社稷重點無可厚非,國際情勢不好、經濟危機出現時,國家資源救市,穩定法人、投資人信心,維持正常的金融機轉,讓國家度過危機,👍值得嘉許,只是這次國安基金護盤的故事,讓人百般尋味。 台股去年創下18650破紀錄新高,隨著國際局勢一起回檔,國安基金決定進場護盤: 第一:當時股市萬八,不是