8

マルチプロセッシングを使用して、辞書に保存されている非常に大量のデータを処理しています。基本的に私がしているのは、辞書に保存されているいくつかの署名をロードし、そこから共有dictオブジェクトを構築し(Manager.dict()によって返される'proxy'オブジェクトを取得)、このプロキシを引数として次の関数に渡すことです。マルチプロセッシングで実行されます。

明確にするために:

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

現在、署名が200万エントリ程度未満であれば、すべてが完全に機能します。とにかく、私は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
---------------------------------------------------------------------------

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

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

ありがとうございました、

ダビデ

4

4 に答える 4

6

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

于 2010-12-26T17:27:01.360 に答える
2

時間を節約し、システム レベルの問題をデバッグする必要をなくすために、580 万のレコード ディクショナリをそれぞれ 200 万以下の 3 つのセットに分割し、ジョブを 3 回実行することができます。

于 2010-12-26T17:24:26.847 に答える
0

あなたが直面していた問題は、dictまたはハッシュテーブルが大きくなるにつれてそれ自体のサイズを変更することだったと思います。最初に、dictには使用可能なバケットのセット数があります。Pythonについてはよくわかりませんが、Perlは8から始まり、バケットがいっぱいになると、ハッシュはさらに8つ(つまり、8、16、32、...)で再作成されます。

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

ここで衝突が発生します。スロットの動的なサイズ設定によりアイテムが順番に追加されるため、バケット内のアイテムが多いほど、関数の取得が遅くなります。

発生する可能性のある問題の1つは、キーが非常に類似しており、同じハッシュ結果を生成することです。つまり、キーの大部分が1つのスロットにあります。ハッシュバケットを事前に割り当てることで、これを排除し、実際に処理時間とキー管理を改善できます。さらに、すべてのスワッピングを行う必要がなくなります。

ただし、まだ空きメモリの量に制限があり、最終的にはデータベースソリューションに移動する必要があると思います。

補足:私はまだPythonを初めて使用します。Perlでは、print%HASHNAMEを実行することでハッシュ統計を確認でき、バケット使用量の分布が表示されます。バケットを事前に割り当てる必要がある場合に備えて、衝突の数を特定するのに役立ちます。これはPythonでも実行できますか?

リッチ

于 2012-02-21T17:43:01.460 に答える
-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)

これは、プロセスごとに 1 GB ではなく、合わせて 1 GB のメモリのみを使用します。これは、最近の OS はフォークの前に作成されたデータのコピー オン ライト シャドウを作成するためです。データへの変更は他のワーカーには表示されず、変更したデータにはもちろんメモリが割り当てられることを覚えておいてください。

いくらかのメモリを使用します。参照カウントを含む各オブジェクトのページが変更されるため、割り当てられます。これが重要かどうかは、データによって異なります。

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

于 2010-12-26T18:31:19.513 に答える