20

私は新しい光沢のあるconcurrent.futuresモジュールをPython 3.2で導入して実験していましたが、ほぼ同じコードで、concurrent.futuresのプールを使用していることがわかりましたwayは、multiprocessing.Poolを使用するよりも遅いです。ProcessPoolExecutorはconcurrent.futuresからマルチプロセスより遅いです。プール

これはマルチプロセッシングを使用したバージョンです:

def hard_work(n): 
    # Real hard work here 
    pass 

if __name__ == '__main__': 
    from multiprocessing import Pool, cpu_count 

    try: 
     workers = cpu_count() 
    except NotImplementedError: 
     workers = 1 
    pool = Pool(processes=workers) 
    result = pool.map(hard_work, range(100, 1000000)) 

そして、これがconcurrent.futures使用している:このEli Bendersky articleから取られたナイーブ因数分解機能を使用して

def hard_work(n): 
    # Real hard work here 
    pass 

if __name__ == '__main__': 
    from concurrent.futures import ProcessPoolExecutor, wait 
    from multiprocessing import cpu_count 
    try: 
     workers = cpu_count() 
    except NotImplementedError: 
     workers = 1 
    pool = ProcessPoolExecutor(max_workers=workers) 
    result = pool.map(hard_work, range(100, 1000000)) 

を、これらは私のコンピュータ上の結果であります(i7,64ビット、Arch Linux):

[[email protected]]─[~/Development/Python/test] 
└[10:31:10] $ time python pool_multiprocessing.py 

real 0m10.330s 
user 1m13.430s 
sys 0m0.260s 
[[email protected]]─[~/Development/Python/test] 
└[10:31:29] $ time python pool_futures.py 

real 4m3.939s 
user 6m33.297s 
sys 0m54.853s 

私はpickleエラーが発生するので、私はPythonプロファイラでこれらをプロファイルできません。何か案は?

+1

私は、あなたの命名規則、特に 'workers'と' hard_work'を愛しています:P –

+0

Cool、innit? :P – astrojuanlu

答えて

34

concurrent.futuresからmapを使用して、各コールに対してFutureオブジェクトを作成エグゼキュータ、に別々に反復可能is submittedからの各要素。次に、先物が返す結果を返すイテレータを返します。
Futureオブジェクトはかなり重いので、コールバック、キャンセル機能、ステータスの確認など、提供するすべての機能を許可するために多くの作業を行います。

これに比べて、multiprocessing.Poolのオーバーヘッドははるかに少なくなります。ジョブをバッチで送信し(IPCオーバーヘッドを減らす)、関数が返す結果を直接使用します。大きなバッチのジョブでは、マルチプロセッシングは間違いなく良い選択肢です。

オーバーヘッドがそれほど重要ではない長時間実行されているジョブ、コールバックで通知を受けたい場合、または完了したかどうかを確認する必要がある場合は、キャンセルすることができます個別に実行します。

個人的なメモ

私は本当にExecutor.mapを使用するために多くの理由を考えることはできません - それはあなたの未来の機能のいずれかを与えるものではありません - タイムアウトを指定する機能を除いて。結果に興味があるのであれば、multiprocessing.Poolのマップ機能のいずれかを使用する方が良いでしょう。

+0

本当にありがとうございました!おそらくバッチで提出することがここの重要なことです。 – astrojuanlu

+7

Python 3.5では、 'ProcessPoolExecutor.map'は' chunksize'キーワード引数を受け取り、IPCオーバーヘッドの問題をやや緩和します。詳細は、この[bug](http://bugs.python.org/issue11271)を参照してください。 – dano

+0

また、Python 3.2では、私の場合、各作業者が作業負荷を終了した後にリソースをクリーンアップするのに役立つマルチプロセスプールに_maxtasksperchild_を設定することができます。 [link](https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing.pool) – Kieleth

関連する問題