2016-10-24 13 views
1

私は20GBのデータを最初にメモリにロードするプログラムを実行しています。次に、N(> 1000)個の独立したタスクを行い、それぞれが20 GBのデータの一部を使用する(読み取り専用)ようにします。私は現在、マルチプロセッシングを介してこれらのタスクを実行しようとしています。しかし、this answerのように、グローバル変数全体がプロセスごとにコピーされます。私の場合、メモリは96GBしかないので、4つ以上のタスクを実行するのに十分なメモリがありません。この種の問題に対する解決策があるかどうか疑問に思うので、あまりにも多くのメモリを消費することなく、すべてのコアを完全に使用することができます。マルチプロセッシンググローバル変数メモリコピー

+0

なぜ大量のデータをメモリにロードしていますか?あなたはそのデータで何をしていますか?理想的には、可能な限り小さなチャンクでデータをロードしたいと考えています。 – sytech

+0

@sytech私の仕事の本質は必要です。私は、各プロセスで必要なデータだけをロードすることを考えていましたが、これは同じデータを複数回ロードすることにつながります。 – wh408

+1

各プロセスはデータ全体を処理する必要がありますが、独自の作業、つまり作業の重複の可能性はありませんか?その場合、あなたは 'Manager.dict()' [ここ](https://docs.python.org/2/library/multiprocessing.html#managers)や 'Manager.list(' ) 'を呼び出し、複数の'プロセス 'を生成します。彼らがすべて同じ作業をしている場合、データをチャンクして、各プロセスに独自のチャンクを渡すことができます。私はあなたがコアよりも多くのプロセスを有効に起動できるとは思っていません。あなたは '> 1000'プロセスを望んでいるようですか? – roganjosh

答えて

3

linuxでは、フォークされたプロセスには、親アドレス空間のコピーライト時のビューがあります。フォークは軽量であり、同じプログラムが親と子の両方で実行されますが、子が異なる実行パスを取る点が異なります。小さなexmample、マルチプロセッシングにこれを適用する

parent: 22642 unchanged 
child: 22643 unchanged 
22643 changed 
22642 unchanged 

import os 
var = "unchanged" 
pid = os.fork() 
if pid: 
    print('parent:', os.getpid(), var) 
    os.waitpid(pid, 0) 
else: 
    print('child:', os.getpid(), var) 
    var = "changed" 

# show parent and child views 
print(os.getpid(), var) 

結果として、この例では、私はグローバル変数にデータをロードします。 Pythonはプロセスプールに送られたデータをpickleするので、私はそれをインデックスのような小さなものにして、グローバルデータ自体を取得させるようにします。

import multiprocessing as mp 
import os 

my_big_data = "well, bigger than this" 

def worker(index): 
    """get char in big data""" 
    return my_big_data[index] 

if __name__ == "__main__": 
    pool = mp.Pool(os.cpu_count()) 
    for c in pool.imap_unordered(worker, range(len(my_big_data)), chunksize=1): 
     print(c) 

Windowsにはプログラムを実行するためのfork-and-execモデルがありません。 Pythonインタプリタの新しいインスタンスを開始し、関連するすべてのデータを子にクローンする必要があります。これは重いリフトです!

+0

Aha。さて、何が起こっているのかを理解する鍵は、コピーオンライトです。あなたがもっと深い理解を持っていなければ、 'mp'について読むときにいくつかのことは矛盾していると感じます。その説明をありがとう、upvote。好奇心のせいで、私はWindowsのせいで 'Managers'を使わなければならない。私の場合は、まず共有リソースを初期化するために別の20GBオブジェクト(元の+ 'Manager' = 40GB)を作成しますか? Docsは、プロセスが_Manager_へのプロキシを介して共有リスト/ dictにアクセスすることを提案しますが、私はテストするために 'mp'で十分なデータを扱ったことがありません。 – roganjosh

+0

ありがとう@tdelaney、結論はPythonのバージョン(私の場合は2.7)と実装方法(pool.map、imap、imap_unordered)に依存していますか? – wh408

+1

@whan - 'map'と' imap'は、すべての処理が完了するのを待って、送信された順に結果を返します。あなたが返品順序を気にしなければ、 'imap_unordered'はより効率的で、結果が大きい場合にはより少ないメモリしか使用しません。マルチプロセッシングは、Python 2.xと3.xではほとんど同じです。 'map'と' imap_unordered'は、順序付けされた結果を望むかどうかによって、どちらも良いオプションです。 – tdelaney

関連する問題