multiprocessing
ライブラリ(python 3.6
)、大きなpd.DataFrame
が引数として関数に渡されます:
from multiprocessing import Pool
import time
def my_function(big_df):
# do something time consuming
time.sleep(50)
if __name__ == '__main__':
with Pool(10) as p:
res = {}
output = {}
for id, big_df in some_dict_of_big_dfs:
res[id] = p.apply_async(my_function,(big_df ,))
output = {u : res[id].get() for id in id_list}
問題は、pickle
ライブラリからエラーが発生することです。
理由: 'OverflowError(' 4GiBより大きいバイトオブジェクトをシリアル化できません '、)'
pickle v4
はより大きなオブジェクトをシリアル化できます 質問関連 、 link ですが、multiprocessing
が使用しているプロトコルを変更する方法はわかりません。
誰かが何をすべきか知っていますか?ありがとう!!
どうやらこのトピックに関して未解決の問題( Issue )があり、この特定の回答( link )に関連するいくつかの関連する取り組みがあります。この回答に基づいて、pickle
ライブラリで使用されているデフォルトのmultiprocessing
プロトコルを変更する方法を見つけました( link )。コメントで指摘されたように、このソリューションはLinuxおよびOSマルチプロセッシングlibでのみ機能します
最初に新しい分離モジュールを作成します
pickle4reducer.py
from multiprocessing.reduction import ForkingPickler, AbstractReducer
class ForkingPickler4(ForkingPickler):
def __init__(self, *args):
if len(args) > 1:
args[1] = 2
else:
args.append(2)
super().__init__(*args)
@classmethod
def dumps(cls, obj, protocol=4):
return ForkingPickler.dumps(obj, protocol)
def dump(obj, file, protocol=4):
ForkingPickler4(file, protocol).dump(obj)
class Pickle4Reducer(AbstractReducer):
ForkingPickler = ForkingPickler4
register = ForkingPickler4.register
dump = dump
次に、メインスクリプトで以下を追加する必要があります。
import pickle4reducer
import multiprocessing as mp
ctx = mp.get_context()
ctx.reducer = pickle4reducer.Pickle4Reducer()
with mp.Pool(4) as p:
# do something
それはおそらくオーバーフローの問題を解決します...しかし、警告、あなたは何かをする前に this を読むことを検討するかもしれませんまたはあなたは私と同じエラーに達するかもしれません:
'i'形式には-2147483648 <=数値<= 2147483647が必要です
(このエラーの理由は、上記のリンクで詳しく説明されています)。つまり、multiprocessing
は、pickle
プロトコルを使用して、すべてのプロセスを通じてデータを送信します。すでに4gb
の制限に達している場合は、関数を次のように再定義することを検討することをお勧めします。入出力メソッドではなく「void」メソッド。このすべてのインバウンド/アウトバウンドデータはRAMの使用量を増やします。おそらく構造(私の場合)によって非効率的であり、それぞれに新しいコピーを作成するよりもすべてのプロセスを同じオブジェクトにポイントする方が良いかもしれません)コール。
お役に立てれば。