2010-12-26 27 views
6

私はマルチプロセッシングを使って辞書に格納された非常に大量のデータを処理しています。基本的に私がやっていることは、ディクショナリに保存されているシグネチャを読み込んで、そこから共有ディクテーションオブジェクトを作成して(Manager.dict()によって返された 'プロキシ'オブジェクトを取得する)、このプロキシを引数として関数に渡しますマルチプロセッシングで実行されます。ただ、明確にするPython:マルチプロセッシングを使って巨大な辞書を共有する

署名が2つの未満で100万エントリまたはそうであれば

signatures = dict() 
load_signatures(signatures) 
[...] 
manager = Manager() 
signaturesProxy = manager.dict(signatures) 
[...] 
result = pool.map (myfunction , [ signaturesProxy ]*NUM_CORES) 

、すべてが完璧に動作します。とにかく、私は5.8Mのキーで辞書を処理する必要があります(の署名のバイナリ形式で4.8 GBのファイルが生成されます)。この場合、プロセスは、プロキシオブジェクトの作成中に死ぬ:

Traceback (most recent call last): 
    File "matrix.py", line 617, in <module> 
signaturesProxy = manager.dict(signatures) 
    File "/usr/lib/python2.6/multiprocessing/managers.py", line 634, in temp 
token, exp = self._create(typeid, *args, **kwds) 
    File "/usr/lib/python2.6/multiprocessing/managers.py", line 534, in _create 
id, exposed = dispatch(conn, None, 'create', (typeid,)+args, kwds) 
    File "/usr/lib/python2.6/multiprocessing/managers.py", line 79, in dispatch 
raise convert_to_error(kind, result) 
multiprocessing.managers.RemoteError: 
--------------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/usr/lib/python2.6/multiprocessing/managers.py", line 173, in handle_request 
    request = c.recv() 
EOFError 
--------------------------------------------------------------------------- 

私がいることがわかり、私はデータ構造が巨大である知っているが、私はRAMの32ギガバイト/ wを搭載したマシンで作業し、トップを実行していますよ署名をロードした後のプロセスは、7GBのRAMを占有します。その後、プロキシオブジェクトの構築が開始され、RAMの使用量は最大17GBのRAMになりますが、32に近づくことはありません。この時点で、RAM使用率は急速に低下し始め、プロセスは上記のエラーで終了します。だから私はこれがメモリ不足のエラーのためではないと思います...

アイデアや提案はありますか?

は、システムレベルの問題を時間を節約し、デバッグを持っていないの関心では、

ダヴィデ

答えて

-3

辞書が読み取り専用の場合、ほとんどのオペレーティングシステムではプロキシオブジェクトは必要ありません。

ワーカーを起動する前に辞書を読み込んで、どこかに手を届かせてください。最も単純な場所は、モジュール全体に対してです。彼らは労働者から読むことができます。

from multiprocessing import Pool 

buf = "" 

def f(x): 
    buf.find("x") 
    return 0 

if __name__ == '__main__': 
    buf = "a" * 1024 * 1024 * 1024 
    pool = Pool(processes=1) 
    result = pool.apply_async(f, [10]) 
    print result.get(timeout=5) 

これは、現代の任意のOSは、フォークの前に作成されたデータのコピー・オン・ライトの影を行いますので、プロセスごとに1GBのない、組み合わせ1GBのメモリを使用しています。データの変更は他の作業者には見られないことを覚えておいてください。変更するデータにはメモリが割り当てられます。

メモリを使用します。参照カウントを含む各オブジェクトのページが変更されるため、割り当てられます。この問題がデータに依存するかどうか。

これは、通常のフォークを実装するすべてのOSで動作します。 Windowsでは動作しません。その(不自由な)プロセスモデルは、各作業者のプロセス全体を再起動する必要があるため、データを共有することはあまりよくありません。

+1

これはWindows 7で動作しますか(現代のOSは間違いありません) –

+0

@Seun:わかりません。それをテストしてみてください。私は、そのプロセスモデルが以前のバージョンよりも現代的であるとは思っていません。 Windowsはこれまで暗黒時代を迎えていました。 –

+1

(無作為な、無作為なdownvotesのためにSOのようなものはありません) –

2

をいただきありがとうございます、多分あなたは約2百万円の3つのセットにあなたの580万レコード辞書を分割することができそれぞれを実行し、ジョブを3回実行します。

+0

私はそれはあなたのタスクはHadoopのために適切であるように、それが聞こえるとにかく、最後に私は辞書全体を再構築する必要があると思いますし、他の操作 –

+0

のためにそれを使用、として最適なソリューションではありませんでした/ MapReduce ...多分あなたはそれをチェックするべきです。 – Fragsworth

6

データベースでこれを試してみませんか?データベースはアドレス可能な/物理的なRAMに限定されず、マルチスレッド/プロセスの使用に安全です。

0

あなたが遭遇していた問題は、ディクテーションまたはハッシュテーブルが成長するにつれてサイズが変更されることでした。最初に、dictには利用可能なバケット数が設定されています。私はPythonについてはわかりませんが、Perlが8で始まり、バケットがいっぱいになると、ハッシュは8つ以上再作成されます。8,16,32、...)。

バケットは、ハッシュアルゴリズムの着陸場所です。 8つのスロットは8つのエントリを意味するものではなく、8つのメモリ位置を意味します。新しい項目が追加されると、そのキーのハッシュが生成され、そのバケットに格納されます。

これは、衝突が発生する場所です。バケット内にあるアイテムが多いほど、スロットの動的サイジングによってアイテムが順番に追加されるため、機能が遅くなります。

キーが非常によく似ていて、同じハッシュ結果を生成するという問題が発生する可能性があります。つまり、キーの大部分が1つのスロットにあります。ハッシュバケットを事前に割り当てることで、これをなくし、実際に処理時間とキー管理を向上させることができます。

しかし、あなたはまだ空き連続メモリの量に制限されていると思うし、最終的にデータベースソリューションに行く必要があります。

サイドノート:私はまだPythonには新しいですが、私はPerlでprint%HASHNAMEを実行することでハッシュ統計を見ることができます。バケット使用の分布を表示します。バケットをあらかじめ割り当てる必要がある場合に、衝突数を特定するのに役立ちます。これはPythonでもできますか?

リッチ

関連する問題