iMind Developers Blog

iMind開発者ブログ

Pythonのmultiprocessingで複数の引数を渡す

概要

multiprocessingで並列処理をする際に引数を複数渡す方法をいつも忘れてしまう。

バージョン情報

  • Python 3.7.3

引数を1つだけ渡す

渡す引数が1つの場合はPool.mapやPool.imapでiterableな引数を渡すことが多い。

import time
from multiprocessing import Pool

def sleep(sec):
    print('start', sec)
    time.sleep(sec)
    print('end', sec)

with Pool(3) as pool:
    pool.map(sleep, range(1, 4))

    # 同時にstartして順に終わる
    #=> start 1
    #=> start 2
    #=> start 3
    #=> end 1
    #=> end 2
    #=> end 3

Processで複数の引数を渡す

Processを使えばだいたいのことはできる。けど管理が面倒。

from multiprocessing import Process

def sleep(sec, arg):
    print('start', sec, arg)
    time.sleep(sec)
    print('end', sec, arg)

processes = [
    Process(target=sleep, args=(i, 'hoge')) 
    for i in range(1, 4)]

for p in processes:
    p.start()
for p in processes:
    p.join()

    #=> start 1 hoge
    #=> start 2 hoge
    #=> start 3 hoge
    #=> end 1 hoge
    #=> end 2 hoge
    #=> end 3 hoge

apply_async

apply_asyncは値が渡しやすく管理も比較的楽。

with Pool(3) as pool:
    sleeps = [pool.apply_async(sleep, (i, 'hoge')) for i in range(1, 4)]
    [f.get() for f in sleeps]

    #=> start 1 hoge
    #=> start 2 hoge
    #=> start 3 hoge
    #=> end 1 hoge
    #=> end 2 hoge
    #=> end 3 hoge

starmap

starmapは [(1, 'foo'), (2, 'hoge')] のような値を渡すと、1つ目の実行には 1, 'foo' が、2つ目の実行には 2, 'hoge' が渡される。

下記のような引数を用意する。

list1 = [1, 2, 3]
list2 = ['foo', 'bar', 'baz']
args = list(zip(list1, list2))
    # => [(1, 'foo'), (2, 'bar'), (3, 'baz')]

starmapで呼び出す。

with Pool(3) as pool:
    pool.starmap(sleep, args)

    #=> start 1 foo
    #=> start 3 baz
    #=> start 2 bar
    #=> end 1 foo
    #=> end 2 bar
    #=> end 3 baz

改定履歴

Author: Masato Watanabe, Date: 2019-07-20, 記事投稿