2017-11-20 7 views
0

私は最近、いくつかの並列プロセスをプールにリファクタリングしてみましたが、プールが純粋なプロセスのほぼ2倍の時間を費やしていたことに驚いていました。それらが同じ数のコアを持つ同じマシン上で実行されていると仮定してください。プールが同じ数のプロセスより遅い理由

共有依存関係:

ここ

https://github.com/taynaud/python-louvain

from community import best_partition 

Processを使用してより高速な実装である私は、誰かがプールを使用して、私の実装は時間がかかっている理由を説明すると、おそらくいくつかのアドバイスを提供できることを願っています。 [UPDATE]はまだ速く、プールの実装と同じアクティブなプロセスの数を制御するためのリファクタリング:

processes = [] 
pipes = [] 

def _get_partition(send_end): 
    send_end.send(best_partition(a_graph, resolution=res, randomize=rand)) 

for idx in range(iterations): 
    recv_end, send_end = Pipe(False) 
    p = Process(target=_get_partition, args=(send_end,)) 
    processes.append(p) 
    pipes.append(recv_end) 

running_procs = [] 
finished_procs = [] 
while len(finished_procs) < iterations: 
    while len(running_procs) < n_cores and len(processes): 
     proc = processes.pop() 
     proc.start() 
     running_procs.append(proc) 

    for idx, proc in enumerate(running_procs): 
     if not proc.is_alive(): 
      finished_procs.append(running_procs.pop(idx)) 

for p in finished_procs: 
    p.join() 

partitions = [pipe.recv() for pipe in pipes] 

そしてここでは遅く、Pool実装です。これは関係なく、プールが指定されているどのように多くのプロセスはまだ遅くはありません:プロセスのプールと束との違いは、(それがいずれかの利益のためにすることができます)がある場合に

pool = Pool(processes=n_cores) 
results = [ 
    pool.apply_async(
     best_partition, 
     (a_graph,), 
     dict(resolution=res, randomize=rand) 
    ) for i in range(iterations) 
] 
partitions = [res.get() for res in results] 
pool.close() 
pool.join() 
+0

最初の例では、より多くのプロセスを潜在的に作成しています。 – Shadow

+0

Shadowに返信してくれてありがとう、私は同じマシン上でそれらを実行していて、プールはマシンが提供しなければならない最大数のコアを使用していました。 – jfunk

+0

時間の測定には正確に何が含まれていますか?両方のケースまたはその一部のコードスニペット全体ですか? – roganjosh

答えて

1

は通常、それはあなたのデータセットであります結果を定義するタスクが実行されます。

あなたのa_graphが何であるか知らずに、私は野生のものかと思うほど大きなものです。プロセスモデルでは、サブプロセスでこれのメモリ内コピーを使用します。プールモデルでは、呼び出されるたびにa_graphのコピーを引数として各ワーカーに送信します。これは実際にはキューとして実装されています。あなたのプロセスモデルでは、Pythonインタプリタがfork()を呼び出すと、サブプロセスはCレベルでこれをコピーします。これは、大規模なPythonオブジェクト、辞書、配列などをキュー経由で送信するよりもはるかに高速です。

タスクが完了するのにわずかな時間がかかる場合は逆になります。この場合、Poolはタスクを既に実行中のプロセスに渡すので、Poolはより優れたソリューションです。各タスクの後にプロセスを再作成する必要はありません。この場合、わずか数秒で実行される多くの新しいプロセスを作成するために必要なオーバーヘッドにより、プロセスの実装が遅くなります。

私が言ったように、これは純粋な推測ですが、あなたの例では、あなたが実際にパラメータとしてあなたの労働者に送信するものとは大きな違いがあり、それが説明かもしれません。

+0

説明をいただきありがとうございます。 – jfunk

関連する問題