mapとclass multiprocessing.pool.Pool#mapの違い

Pythonのmultiprocessingモジュールをたどっていくと、class multiprocessing.pool.Poolクラスというものがあります。

このクラスに、mapというインスタンスメソッドがあるそうな。

通常のmap関数のマルチプロセス版っぽいやつみたいです。

multiprocessingのドキュメントより引用―
multiprocessing モジュールでは threading モジュールには似たものがない API も導入しています。その最たるものが Pool オブジェクトです。

この「っぽい」というのが曲者で、説明を読んでいるだけではいまいち全貌がつかめません。
そいうときは、実験するに限ります。

通常mapでサンプルスクリプト

以下のようなスクリプトを書きました。

(ファイル名) test.py

import time
import random
import multiprocessing.pool

random.seed(time.time())

# map関数に渡す関数
# プログラミング言語名と文字列の長さを返す。
# lang <- プログラミング言語名
def name_and_len(lang):
    print("{} start.....".format(lang))     # 関数に入ったことを通知する。
    time.sleep(random.random())             # ある時間だけ待つ。
    return '{}({})'.format(lang, len(lang)) # 言語名 + 文字列長を返す。

mp = multiprocessing.pool.Pool() # 今回は変数mpは使用しない。

lang = ['Python', 'Ruby', 'PHP']
iter = map(name_and_len, lang, 5) # (A)この部分を後程いろいろと変更する。

print(lang)
time.sleep(1) 

# たった今作ったばかりのイテレーターをループで回して、表示する。
for i in iter:
    print(i)

実行してみると、

$ python3 test.py
['Python', 'Ruby', 'PHP']
※1秒経過後、以下が表示される。
Python start.....
Python(6)
Ruby start.....
Ruby(4)
PHP start.....
PHP(3)

つまり、name_and_len関数は、イテレーターからデータを取り出すときに実行されます。

class multiprocessing.pool.Pool版mapのサンプルスクリプト

続きまして、通常のmap関数をclass multiprocessing.pool.Poolクラスのインスタンスメソッド版のmapに置き換えてみます。

すなわち、(A)のコードを以下のように書き換えます。

iter = mp.imap(name_and_len, lang, 5) # (A)

これを実行すると、

['Python', 'Ruby', 'PHP']
※1秒待つことなく以下が表示される。
Python start.....
Ruby start.....
PHP start.....
Python(6)
Ruby(4)
PHP(3)

呼び出し側の処理が止まっている間に、multiprocessing.pool.Poolオブジェクト側で処理が行われます。

〜鋭意実験中〜

参考文献

入門Python 3 (オライリー)

Pythonプログラミング物語 © 2016 Frontier Theme