[英]How to share an instance variable between multiple processes
我有一個 class 定義和使用如下,其中包括在多處理池上下文中調用的方法:
from multiprocessing import Pool
class MyClass:
def __init__(self, big_object):
self.big_object = big_object
def compute_one(self, myvar):
return self.big_object.do_something_with(myvar)
def compute_all(self, myvars):
with Pool() as pool:
results = pool.map(compute_one, myvars)
return results
big_object = pd.read_csv('very_big_file.csv')
cls = MyClass(big_object)
vars = ['foo', 'bar', 'baz']
all_results = cls.compute_all(vars)
這“有效”,但問題是big_object
在 RAM 中占用了幾個 Gb,並且使用上面的代碼,這個大的 object 被multiprocessing.Pool
啟動的每個進程復制到 RAM 中。
如何修改上面的代碼,使big_object
在所有進程之間共享,但仍然可以定義在class實例化?
- 編輯
我正在嘗試做的事情的一些背景可能有助於完全確定一種不同的方法。
在這里, big_object
是一個 1M+ 行 Pandas dataframe,有幾十列。 compute_one
根據特定列計算統計信息。
一個簡化的高級視圖將是(非常總結):
current_col = manufacturer
)rem_col
:
big_object.groupby([current_col, rem_col]).size()
最終結果如下所示:
制造商 | country_us | 國家/地區 | client_male | 女客戶 |
---|---|---|---|---|
寶馬 | 15 | 18 | 74 | 13 |
奔馳 | 2個 | 24 | 12 | 17 |
捷豹 | 48 | 102 | 23 | 22 |
所以從本質上講,這是關於計算整個源 dataframe 中每一列、每隔一列的統計信息。
對於給定的current_col
,在這里使用 multiprocessing 可以並行計算remaining_cols
的所有統計數據。 在這些統計數據中,不僅有sum
,還有mean
(對於剩余的數字列)。
一種使用全局變量(從類外部實例化的全局big_object
)的骯臟方法將整個運行時間從 5 多個小時增加到大約 20 分鍾。 我唯一的問題是我想避免這種全局 object 方法。
一種解決方案是使MyClass
成為托管的 class ,就像使用multiprocessor.Manager().dict()
創建的托管字典一樣。 為確保“大對象”只有一個副本,首先我將修改MyClass.__init__
以采用 CSV 文件路徑參數。 這樣“大對象”只在管理器的進程中構建。 其次,我將從MyClass
中刪除compute_all
邏輯並調用multiprocessing.pool.Pool.map
方法,這樣作為 worker function 傳遞的是托管對象的代理。
您在空間上節省了什么,您就放棄了一些性能,因為每次調用方法compute_one
或多或少地等同於對實際執行它的管理器進程的遠程方法調用。
from multiprocessing import Pool
from multiprocessing.managers import BaseManager
import pandas as pd
class MyClassManager(BaseManager):
pass
class MyClass:
def __init__(self, path):
self.big_object = pd.read_csv(path)
def compute_one(self, myvar):
# For demo purposes just check if column myvar exists in dataframe:
return myvar in self.big_object
# Required for Windows:
if __name__ == '__main__':
MyClassManager.register('MyClass', MyClass)
with MyClassManager() as manager:
cls = manager.MyClass('very_big_file.csv')
# vars is a built-in function name and should not be used:
my_vars = ['foo', 'bar', 'baz']
with Pool() as pool:
all_results = pool.map(cls.compute_one, my_vars)
print(all_results)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.