簡體   English   中英

如何在多個進程之間共享一個實例變量

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM