クラスの内部で並列処理を利用したメソッドを利用する

やりたいこと

pythonクラスで、並列処理を利用したメソッドを実装したい。

つまり、classの中で、multiprocessing.Pool を利用したい。

しかし、普通のやり方ではできない。そこで、ちょっとした工夫が必要になる。

※ ただし、multiprocessing.Process ならメソッドで使える。ただし、 multiprocessing.Processはプロセスの管理とか面倒なのだ

解決法

通常、クラスの中で、multiprocessing.Poolを利用したメソッドを書き、別のメソッドを並列処理させようとすると、エラーがでる。

PicklingError: Can't pickle : attribute lookup __builtin__.instancemethod failed

つまり、「引数が展開できへんで〜」と言っている。これはmultiprocessing.Poolの仕様なのだ。

じゃあ、どうするか、っていうと、クラスの外部に引数を展開して、目的のクラスメソッドを呼び出して、値を返す関数を定義することになる。

動かないコード

from multiprocessing import Pool
import time
 
class C:        
    def f(self, name):
        並列処理をしたいメソッド
     
    def run(self):
        pool = Pool(processes=2)
        pool.map(self.f, [1, 2, 3, 4])
 
if __name__ == '__main__':
    c = C()
    c.run()

ここで、self.fをcallせずに、「メソッドfをクラスメソッドとして呼び出す関数」を作成する

from multiprocessing import Pool
import time
 
def unwrap_self_f(arg, **kwarg):
    # メソッドfをクラスメソッドとして呼び出す関数
    return C.f(*arg, **kwarg)
 
from multiprocessing import Pool
import time
 
class C:        
    def f(self, name):
        並列処理をしたいメソッド
     
    def run(self):
        pool = Pool(processes=2)
        pool.map(unwrap_self_f, [1, 2, 3, 4])
 
if __name__ == '__main__':
    c = C()
    c.run()

こうすると、動いてくれる。

ちなみに、この内容はここ の英訳みたいなもんです。