読者です 読者をやめる 読者になる 読者になる

サブロウ丸

お気軽に..

Python multiprocessingで並列処理

pythonの標準モジュールmultiprocessingを使用すれば、並列処理を行うことができます。

Pool

map

基本的な使い方は

from multiprocessing import Pool
with Pool(processes=None) as pool:
    pool.map(func, iter)

Poolの引数であるprocessingには並列処理に使用するプロセス数を指定します。
デフォルト値であるNoneを渡すと, processesにはos.cpu_count()(現在の環境でのプロセス数)が代入されます。


pool.map(func, iter[, chunksize])イテレータの各要素を引数とした関数を並列で回してくれます。 例えば、

from multiprocessing import Pool

def hoge(x):
    print(x + 'が、おいしい')

fruits = ['りんご', 'ぶどう', 'なし', 'みかん', 'かき']

with Pool(processes=2) as pool:
    pool.map(hope, fruits)

のようなコードを実行すると、

ぶどうが、おいしい
りんごが、おいしい
なしが、おいしい
みかんが、おいしい
かきが、おいしい

という、出力を得ます。


chunksizeについて

ちなみに、並列処理はmapに入力したイテレータがchunksizeの長さ分だけ切り出されてジョブとして各プロセスに渡されます。
各プロセスに渡されたジョブが完了すると、また次のジョブがイテレータから切り出される仕組みです。
デフォルトでは、chunksizeは使用するプロセス数*4となっています。


例えば一つ一つの処理が重たいものが大量に存在する場合は、
特に重たい処理をイテレータの序盤に持ってくるのに加え、
chunksizeを小さい整数(例えば1)に設定する方が効率よくcpuを使える(i.e. ジョブ全体が終了するまでに、休むプロセス数が減る)と思うのですが、どうでしょうか。。


starmap

関数の引数を増やしたい場合は、starmapを使えば良いです。

from multiprocessing import Pool

def hoge(x, y):
    print('{}は{}よりもおいしい'.format(x, y))

fruits = [('りんご', 'いちじく'), ('ぶどう', 'いちご'), ('なし', 'スイカ')]

with Pool(processes=2) as pool:
    pool.starmap(hope, fruits)
りんごはいちじくよりもおいしい
なしはスイカよりもおいしい
ぶどうはいちごよりもおいしい