2017-11-28 22 views
0

編集のために働いていない:アップルMBPを実行 2017 2.8GHzのi7の4コアを持つモデル14,3:Pythonのマルチプロセッシングが遅く、本当にオブジェクトメソッド

multiprocessing.cpu_count() 
8 

私が行ってるオブジェクトのリストを持っていますPythonでオブジェクトごとに1回オブジェクトメソッドを実行します。このプロセスは遺伝的アルゴリズムのためのものなので、私はそれを高速化することに興味があります。基本的には、データリストのデータで環境を更新するたびに、オブジェクト(ゲノム)は環境から値を取り出し、それ自身の内部値を参照するなど、少しの計算を実行します。
私がやっている:

from multiprocessing import Pool 

class Individual(object): 
    def __init__(self): 
    self.parameter1 = None 
    self.parameter2 = None 

    def update_values(): 
     # reads the environment variables, does math specific to each instance 
     # updates internal parameters 
     a, b, c, d = environment_variables 
     self.parameter1 = do_math(a, b, c, d, 
            self.parameter1, self.parameter2) 
     self.parameter2 = do_math(a, b, c, d, 
            self.parameter1, self.parameter2) 


data_list = [data1, data2, data3, ..., data1000] 
object_list = [object1, object2, object3, ..., object20000] 

を私はこれを実行した場合:

for newdataset in data_list: 
    update_parameters(newdataset) 
    for object in object_list: 
     object.update_values() 

をそれは私がマルチプロセッシング/マップを使用して、これを分割しようとした場合よりも高速ずっとです:

def process_object(object): 
    object.update_values() 

for newdataset in data_list: 
    update_parameters(newdataset) 
    with Pool(4) as p: 
     p.map(process_object, object_list) 

object_listの長さが200(20000ではなく)で実行すると、合計スレッド時間はシングルスレッドモードで14.8秒になります。 マルチプロセッシングモードで同じものを実行すると、合計時間は...まだ待っています... ok ... 211秒です。
また、関数が何をすべきかとは言いません。私はここで何が欠けていますか?各オブジェクトの値をチェックすると、それらは全く更新されていないように見えます。

+0

どのような処理が行われているかについて少し詳しく説明できますか?また、コア数はいくつですか?どのようなOSですか? – vasia

+0

また、プロセスに渡されるすべてのパラメータは、シリアル化可能でなければなりません。したがって、object_listにはどのようなオブジェクトがありますか(クラスインスタンスはデフォルトではシリアル化されません) – Sergius

+0

マルチプロセッシングは[pickle](https://docs.python.org/3/library/pickle.html)を使用してデータをシリアライズし、クラスと再帰構造を処理できます。 –

答えて

0

私は並列化をちょっと別々に分割します。 update_parametersで何が起こっているのかを知るのは難しいですが、私はその呼び出しを並列化します。なぜそれを離れる?興味のある操作全体をいくつかの関数でラップすることができますか?

また、これは重要です。メインプロセスの場合は、プールを開く必要があります。ですから、マルチプロセッシングを使用する場合、あなたは両方の方法をシリアル化してデータを転送しているラインに

if __name__ == '__main__': 
    with Pool(multiprocessing.cpu_count()) as p: 

+0

あなたのコメントの後に更新が完了する前に、あなたが答えてくれたことをお詫び申し上げます。私は主な機能でプールを実行していませんが、私は窓から走っていませんので、これは正しいでしょうか? –

+0

@Notachanceこの場合、問題はあなたのプログラムロジックとあなたが呼んでいる機能の内容と関係しています。もしあなたがより詳細を提供できるなら、私はあなたを助けることができます。 – vasia

+1

また、このSOの投稿は役に立つかもしれません - https://stackoverflow.com/questions/26911882/python-multiprocessing-why-much-slower 可能であれば、各プロセスが別々のファイルからそれを読み取ることができますこれはあなたのメインプロセスがすべてを読み込んでからIPC経由で子どもにデータを配布するよりも速くなります。 – vasia

0

を追加します。この場合、これにはupdate_valuesを呼び出すためにインデントする各オブジェクトが含まれます。私はあなたのモデルを繰り返していると思っています。つまり、彼らはかなり多くのものを前後に送るでしょう。さらに、map()は結果のリストを返しますが、process_objectはNoneを返します。つまり、モデルをシリアライズして別のプロセスに送信し、そのプロセスを実行してモデルを更新してから、Noneを返し、更新されたモデルを破棄してから、Noneの結果リストを破棄します。モデルを返す場合:

def process_object(object): 
    object.update_values() 
    return object 

... 

object_list = p.map(process_object, object_list) 

実際にはいくつかの結果が出るかもしれませんが、ほぼ確実に遅くなります。特に、あなたのプロセスプールはdata_listやそれに類するもの( "環境"?)を持たないでしょう - あなたがPool.map()を通過したものだけを受け取ります。

テンソルフローやMPIなどの他のツールの使用を検討してください。少なくともsharing state between processesを読んでください。また、おそらく、反復ごとにプロセスプールを再作成するべきではありません。これは、Windowsなどの一部のプラットフォームでは非常に高価です。

+0

私はリスト内のパラメータを更新し、それらのコピーを返さないことを望んでいました。マルチプロセッシングがすべてを漬けていることに気付かなかった。こんにちは –

+0

ありがとうございます。私はオブジェクトが互いに全く話していないので、私が "プロセス間で共有する"ことを認識しませんでした。私はいくつかのことを試してみると戻ってくる。 –