Pythonでのmultiprocessing
Python2.6から導入されたmultiprocessing.Poolを用いることで実現できます。
実行可能コア数の取得(指定)
↓
Poolインスタンスの生成
↓
マルチプロセス実行する関数の引数を用意
↓
実行
use_multi.py
from multiprocessing import Pool
import multiprocessing as multi
def calc(n): # マルチプロセス実行したい関数
return n * n
def main():
n_cores = multi.cpu_count() # 実行可能コア数の取得
p = Pool(n_cores)
args = list(range(10)) # fugaに与える引数のリスト
res = p.map(calc, args) # マルチプロセスの実行
print(res) # 各プロセスで実行した関数の戻り値がリストで返ってくる
if __name__ == "__main__":
main()
$ python use_multi.py
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
便利だけど痛い制約があった
マルチプロセス実行する関数が
- クラスのインスタンスメソッド
- 匿名関数
- 関数中で定義した関数
の場合にはpickle関連のエラーが出て使用できませんでした。
use_multi.py
from multiprocessing import Pool
import multiprocessing as multi
class Calc:
def square(self, n):
return n * n
def calc_square_usemulti(self, args):
n_cores = multi.cpu_count()
p = Pool(n_cores)
res = p.map(self.square, args)
print(res)
def main():
calc = Calc()
args = list(range(10))
calc.calc_square_usemulti(args)
if __name__ == "__main__":
main()
3.2以前
$ python use_multi.py
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed
Python 3.3.7から対応された模様
どうやらmethodがpickle可能になったらしく、インスタンスメソッドでも問題なく利用できるようになりました。オブジェクト指向プログラミング等にも使用できるのは大変嬉しいですね。
3.3以降
$ python use_multi.py
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
終わりに
最初、昔はインスタンスメソッド等をmultiprocessing.Poolで使うとエラーが出るということを知らずに使っていたんですよね。ある日、別なエラーで色々調べているうちにインスタンスメソッド等は使えないという記事ばかり出てきて、なんで自分は使えているんだろう?と疑問に思って調べてみて発覚しました。ネットには対応した等の記事がなかったので一応まとめました。