(4/5追記) Pickleした一時ファイルで受け渡すパターン
(9/4追記) Windows対応版
デコレータを作っておいて、既存の関数を書き直さずに子プロセスに処理を投げます。
test.py
import os
from multiprocessing import Process, Queue
# デコレータ
def mp(func):
def _f(*args, **kwargs):
def _p(*args, **kwargs):
al = list(args)
q = al.pop()
q.put(func(*al, **kwargs))
queue = Queue()
argsl = list(args)
argsl.append(queue)
proc = Process(target=_p, args=argsl, kwargs=kwargs)
proc.start()
proc.join()
return queue.get()
return _f
# 子プロセスで実行して結果を返す
@mp
def mp_test(a, b=None):
return (a + b, os.getpid())
result, child = mp_test(1, 2)
print("parent: {}".format(os.getpid()))
print("child: {}".format(child)
print(result)
(4/5追記) Pickleした一時ファイルで受け渡すパターン
データサイズが大きい場合
test2.py
import os
import pickle
from multiprocessing import Process
# デコレータ
def pickle_file(func):
def _f(*args, **kwargs):
def _p(*args, **kwargs):
al = list(args)
n = al.pop()
res = func(*al, **kwargs)
with open(n, "wb") as f:
pickle.dump(res, f)
tmp_name = "_tmp.pickle"
argsl = list(args)
argsl.append(tmp_name)
proc = Process(target=_p, args=argsl, kwargs=kwargs)
proc.start()
proc.join()
with open(tmp_name, "rb") as f:
result = pickle.load(f)
os.remove(tmp_name)
return result
return _f
# 子プロセスで実行して結果を返す
@pickle_file
def mp_test(a, b=None):
return (a + b, os.getpid())
result, child = mp_test(1, 2)
print("parent: {}".format(os.getpid()))
print("child: {}".format(child)
print(result)
(9/4追記) Windows対応版
Windowsではプロセス開始方式がspawnなので、targetで渡す関数がpickle化できなければなりません。ネストした関数はpickle化できないので、この手法は使えません。
Windowsの場合は何の面白みも無いですがクラスを作成します。
test_win.py
import os
import pickle
import multiprocessing as mp
class FileBasedIPC(object):
def __init__(self, func):
self.func = func
def _f(self, *args, **kwargs):
tmp_name = "_tmp.pickle"
argsl = list(args)
argsl.append(tmp_name)
proc = mp.Process(target=self._p, args=argsl, kwargs=kwargs)
proc.start()
proc.join()
with open(tmp_name, "rb") as f:
result = pickle.load(f)
os.remove(tmp_name)
return result
def _p(self, *args, **kwargs):
al = list(args)
n = al.pop()
res = self.func(*al, **kwargs)
with open(n, "wb") as f:
pickle.dump(res, f)
def __call__(self):
return self._f
# 子プロセスで実行して結果を返す
def mp_test(a, b=None):
return (a + b, os.getpid())
result, child = FileBasedIPC(mp_test)()(1, 2)
print("parent: {}".format(os.getpid()))
print("child: {}".format(child)
print(result)