Pythonのfor文並列化について(joblib)

概要

joblibの使い方と共に,どのようなときに使うべきかを確かめました.


使い方

実際の使い方はこのページ最後にあるソースコードを参考にしてください.

まず,以下のプログラムを並列化することにします.

# iのi乗を返す関数
def process(i):
    return i ** i

# [0, 1, 2, 3, .. , 9]というリストを生成
lst = list(range(0, 10))

# lstの中身をそれぞれ処理 
for i in lst:
    lst[i] = process(i)
# この時点でlstは[1, 1, 4, 27, 256, 3125, .. , 387420489]となる

これをjoblibを使って並列化するにはfor文を以下のように書き換えます.

# lstの中身をそれぞれ処理 
lst = Parallel(n_jobs=-1, verbose=0)([delayed(process)(i) for i in lst])

これで全く同じ結果が得られます.

n_jobsはjobの数で,verboseは出力の頻度を設定しています.

n_jobs = -1で最大job数を割り当てられます.

また,verboseは0から10まで設定でき,0にするとjoblibの出力がなくなります.


いつ使うか

このページの最後に書いたプログラムの実行結果から,遅延が0.001秒(1ミリ秒)でもあるならばjoblibを使ったほうが速くなることが分かりました.

ローカルのみで完結する通常の処理はjoblibを使わずに書き,ネットワークを扱うとき等の遅延が発生する処理はjoblibを使うといいでしょう.


ソースコード

from time import time
from time import sleep
from joblib import Parallel, delayed
r = range(0, 1000)

# 遅延が0.01秒の場合
def process_1(data):
    sleep(0.01)
    return data ** data

# 遅延が0.001秒の場合
def process_2(data):
    sleep(0.001)
    return data ** data

# 遅延がない場合
def process_3(data):
    return data ** data

for process in [process_1, process_2, process_3]:
    # 変数初期化
    list_1 = list(r)
    list_2 = list(r)
    
    # 計測開始
    start = time()

    # 処理(joblibなし)
    for i in list_1:
        list_1[i] = process(i)

    # 計測終了
    time_1 = time() - start
    print("time_1:", time_1)

    # 計測開始
    start = time()

    # 処理(joblibあり)
    list_2 =\
    Parallel(n_jobs=-1, verbose=0)([delayed(process)(data) for data in list_2])

    # 計測終了
    time_2 = time() - start
    print("time_2:", time_2)

    # データ比較
    print(list_1 == list_2)
Tweet