Help us understand the problem. What is going on with this article?

Python3のマルチプロセスPoolのメソッドはimap_unorderedを使うべし

More than 3 years have passed since last update.

Python3のマルチプロセスPoolのメソッドが沢山あってどれを使えばいいのか分からなかったので調べました。

map関数

map関数は全ての結果が出るまでブロックします。

コードを実行してみると

map.py
from multiprocessing import Pool
from time import sleep
import time

start = time.time()

def do(waitTime):
    print("do waitTime:{} 開始から{}秒経過".format(waitTime,time.time() - start))
    sleep(waitTime)
    return waitTime

if __name__ == '__main__':
    waitTimes = [3,2,1]
    with Pool(10) as p:
        for result in p.map(do,waitTimes):
            print("result waitTime:{} 開始から{}秒経過".format(result,time.time() - start))

結果は

do waitTime:3 開始から0.03541707992553711秒経過
do waitTime:2 開始から0.03555130958557129秒経過
do waitTime:1 開始から0.03568387031555176秒経過
result waitTime:3 開始から3.0372514724731445秒経過
result waitTime:2 開始から3.0373241901397705秒経過
result waitTime:1 開始から3.037338972091675秒経過

for result in p.map(do,waitTimes):行の戻り値はlist型ですべてのプロセスが終了するまでfor文は実行されません

imap関数

imap関数はmap関数の遅延評価版です。imap関数の戻り値はイテレータを返します。戻り値が確定したプロセスがあれば他のプロセスの完了を待たずにfor文を実行できます。しかし、渡した順番と同じ順番で返さなければならない制約があるために最初のプロセスが終了しなければ、他の処理が終了していてもいつまでたってもfor文が実行されません。

imap.py
from multiprocessing import Pool
from time import sleep
import time

start = time.time()

def do(waitTime):
    print("do waitTime:{} 開始から{}秒経過".format(waitTime,time.time() - start))
    sleep(waitTime)
    return waitTime

if __name__ == '__main__':
    waitTimes = [3,2,1]
    with Pool(10) as p:
        for result in p.imap(do,waitTimes):
            print("result waitTime:{} 開始から{}秒経過".format(result,time.time() - start))
do waitTime:3 開始から0.03740239143371582秒経過
do waitTime:2 開始から0.03748369216918945秒経過
do waitTime:1 開始から0.0376131534576416秒経過
result waitTime:3 開始から3.041029930114746秒経過
result waitTime:2 開始から3.041118621826172秒経過
result waitTime:1 開始から3.0411417484283447秒経過

imap_unordered関数

イテレーターが返す結果の順番が任意の順番で良いと見なされることを除けば imap() と同じです。

imap.py
from multiprocessing import Pool
from time import sleep
import time

start = time.time()

def do(waitTime):
    print("do waitTime:{} 開始から{}秒経過".format(waitTime,time.time() - start))
    sleep(waitTime)
    return waitTime

if __name__ == '__main__':
    waitTimes = [3,2,1]
    with Pool(10) as p:
        for result in p.imap_unordered(do,waitTimes):
            print("result waitTime:{} 開始から{}秒経過".format(result,time.time() - start))
do waitTime:3 開始から0.03511857986450195秒経過
do waitTime:2 開始から0.035273075103759766秒経過
do waitTime:1 開始から0.035429954528808594秒経過
result waitTime:1 開始から1.0369133949279785秒経過
result waitTime:2 開始から2.0377516746520996秒経過
result waitTime:3 開始から3.038750171661377秒経過

おおうっ!処理が完了したプロセスがあれば他の処理を待たずに実行されています!

まとめ

Python3のマルチプロセスPoolのメソッドはimap_unorderedを使うべし

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away