popup mlv

swiftのサンプルを動かしてみたり。

pythonのマルチプロセス制御はかんたんという話

pythonで並列処理してみるという話です。数万件のデータを処理するときなど処理がおそすぎて結果が出てくるまでに日が暮れてしまうというときは一部をマルチプロセス化して処理するのはどうでしょうか。制約は多いですが非常に簡単にできます。

シングルスレッドで動かしている間に片手間でマルチプロセス化できるでしょう。コア数分だけ早くなるのでお手軽です。早くなった分だけ失敗できる!
参考
17.2. multiprocessing — プロセスベースの並列処理 — Python 3.6.1 ドキュメント

制約

  • if name == ‘main’: を必ず使うこと
  • 引数は1つしか送れない

などなどsubプロセスから関数を呼び出したりはできるので複雑なこともできなくはないです。この場合、引数が1つしか送れないのが最大の弱点ですが、実はjoblibやwrapperを挟むと送れます。

内容

していることはlist1の数字をmp_subへ送ってlist2と同じところを取り出して足し算をしてl1, l2, retの3つをメインスレッドへ返します。

from multiprocessing import Pool

# スレッド数
proc = 3
# データ
list1 = range(5)
list2 = range(0, 500, 100)

def main():
    """メインスレッド"""
    with Pool(processes=proc) as p:
        print("サブスレッドへ")
        poolist = p.map(mp_sub, list1)

    print("メインスレッド")
    for l1, l2, ret in poolist:
        print("main : {} , {} , {}".format(l1, l2, ret))

def mp_sub(l1):
    """マルチプロセス化"""
    l2 = list2[l1]
    ret = l1 + l2
    print("mp_sub: {} + {} = {}".format(l1, l2, ret))
    return l1, l2, ret

if __name__ == '__main__':
    main()

結果

サブスレッドへ
mp_sub: 0 + 0 = 0
mp_sub: 1 + 100 = 101
mp_sub: 2 + 200 = 202
mp_sub: 3 + 300 = 303
mp_sub: 4 + 400 = 404
メインスレッド
main : 0 , 0 , 0
main : 1 , 100 , 101
main : 2 , 200 , 202
main : 3 , 300 , 303
main : 4 , 400 , 404

最後に

もし引数を復数渡す場合が出てきたときはjoblibを使ったほうが簡単にかけます。4C/8TのCPUの場合、proc=6程度に抑えておくと他の作業もしながらそこそこ早くなると思います。Ryzen 7 1800X 8C/16Tの場合はもっと早くなりそうです。