web-dev-qa-db-ja.com

python multiprocessing-OverflowError( '4GiBより大きいバイトオブジェクトをシリアル化できません')

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が使用しているプロトコルを変更する方法はわかりません。

誰かが何をすべきか知っていますか?ありがとう!!

6
Pablo

どうやらこのトピックに関して未解決の問題( 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の使用量を増やします。おそらく構造(私の場合)によって非効率的であり、それぞれに新しいコピーを作成するよりもすべてのプロセスを同じオブジェクトにポイントする方が良いかもしれません)コール。

お役に立てれば。

3
Pablo