18

次のように要約できるプログラムを作成しました。

def loadHugeData():
    #load it
    return data

def processHugeData(data, res_queue):
    for item in data:
        #process it
        res_queue.put(result)
    res_queue.put("END")

def writeOutput(outFile, res_queue):
    with open(outFile, 'w') as f
        res=res_queue.get()
        while res!='END':
            f.write(res)
            res=res_queue.get()

res_queue = multiprocessing.Queue()

if __name__ == '__main__':
    data=loadHugeData()
    p = multiprocessing.Process(target=writeOutput, args=(outFile, res_queue))
    p.start()
    processHugeData(data, res_queue)
    p.join()

実際のコード (特にwriteOutput()) はもっと複雑です。writeOutput()引数として取るこれらの値のみを使用します (つまり、 を参照しませんdata) 。

基本的に、巨大なデータセットをメモリにロードして処理します。出力の書き込みはサブプロセスに委任されます (実際には複数のファイルに書き込み、これには多くの時間がかかります)。そのため、1 つのデータ項目が処理されるたびに、それが res_queue を通じてサブプロセスに送信され、必要に応じて結果がファイルに書き込まれます。

サブプロセスは、ロードされたデータにアクセスしたり、読み取ったり、変更したりする必要はありませんloadHugeData()。サブプロセスは、メインプロセスが送信したものを使用するだけで済みますres_queue。そして、これは私の問題と質問につながります。

サブプロセスが巨大なデータセットの独自のコピーを取得しているように思えます(でメモリ使用量をチェックするときtop)。これは本当ですか?もしそうなら、どうすればidを回避できますか(本質的に二重メモリを使用して)?

私は Python 2.6 を使用しており、プログラムは Linux で実行されています。

4

1 に答える 1

29

このモジュールは、現在のプロセスのコピーを作成するシステム コールmultiprocessingに効果的に基づいています。fork巨大なデータをロードするfork(または作成するmultiprocessing.Process) ため、子プロセスはデータのコピーを継承します。

ただし、実行しているオペレーティング システムが COW (コピー オン ライト) を実装している場合、親プロセスまたは子プロセス (親プロセスと子プロセスの両方) でデータを変更しない限り、実際には物理メモリ内のデータのコピーは 1 つだけです。仮想アドレス空間は異なりますが、同じ物理メモリ ページを共有します)。その場合でも、追加のメモリは変更に対してのみ割り当てられます (pagesize増分で)。

multiprocessing.Process巨大なデータをロードする前に呼び出すことで、この状況を回避できます。次に、親プロセスにデータをロードするときに、追加のメモリ割り当てが子プロセスに反映されません。

編集: @Janne Karila のコメントを回答に反映させると、関連性が非常に高くなります: "

于 2013-02-07T11:31:54.627 に答える