Pythonではmultithreading よりもmultiprocessingの方がCPUのコアを有効に使用できるが,前の例だとCtrl+Cで停止したときにプロセスが残る.
WinPython 3.7では少し改善しているので対策コードが追加できる.
メインのプロセスから,terminate()を実行するととりあえず子プロセスは消える.
実際には残るらしい.
その場合にはProcessのコンストラクタにdaemon=Falseを指定する
最初に考えたコードは次のようなもの... しかし,実際にはうまくいっていない感がある
import numpy as np
from multiprocessing import Process
import multiprocessing as mp
def calc(queue, i_range, arg1, arg2, arg3):
print('Start: {}\r\n'.format(mp.current_process().name))
a = arg1[i_range] + arg2[i_range];
b = arg2[i_range] + arg3[i_range];
c = arg3[i_range] + arg1[i_range];
queue.put([a, b, c])
if __name__ == '__main__':
x = np.linspace(0, 10000, 10000);
y = np.linspace(10000, 0, 10000);
z = np.linspace(0, 10000, 10000) - 5000;
mp_size = 4
ps = [];
queue = mp.Queue()
results = dict()
for i in range(mp_size):
ps.append(mp.Process(target=calc, args=(queue, range(x.shape[0]*i//mp_size, x.shape[0]*(i+1)//mp_size), x, y, z), name="{}".format(i+1), daemon=False))
for p in ps:
p.start()
try:
for i in range(mp_size):
results[i] = queue.get();
except KeyboardInterrupt:
for p in ps:
p.terminate()
a = 0;
b = 0;
c = 0;
for i in range(mp_size):
a += np.asscalar(np.sum(results[i][0]));
b += np.asscalar(np.sum(results[i][1]));
c += np.asscalar(np.sum(results[i][2]));
print('{},{},{}'.format(a, b, c))
無理やり止めるコードを追加しなおしたのが以下のコードである.
無理やり止めているのでidleでデバッグしていると例外などが発生したって確認できなくなる.ただしエンドユーザには関係なくなる.
import numpy as np
from multiprocessing import Process
import multiprocessing as mp
import signal
import sys
ps = [];
def calc(queue, i_range, arg1, arg2, arg3):
print('Start: {}\r\n'.format(mp.current_process().name))
a = arg1[i_range] + arg2[i_range];
b = arg2[i_range] + arg3[i_range];
c = arg3[i_range] + arg1[i_range];
queue.put([a, b, c])
def handler(signum, frame):
global ps;
for p in ps:
if p.is_alive():
try:
p.terminate()
except AssertionError:
pass
print('terminate {}'.format(p.pid));
sys.exit(0);
if __name__ == '__main__':
signal.signal(signal.SIGINT, handler);
x = np.linspace(0, 10000, 10000);
y = np.linspace(10000, 0, 10000);
z = np.linspace(0, 10000, 10000) - 5000;
mp_size = 4
queue = mp.Queue()
results = dict()
for i in range(mp_size):
ps.append(mp.Process(target=calc, args=(queue, range(x.shape[0]*i//mp_size, x.shape[0]*(i+1)//mp_size), x, y, z), name="{}".format(i+1), daemon=False))
for p in ps:
p.start()
for i in range(len(ps)):
results[i] = queue.get();
a = 0;
b = 0;
c = 0;
for i in range(mp_size):
a += np.asscalar(np.sum(results[i][0]));
b += np.asscalar(np.sum(results[i][1]));
c += np.asscalar(np.sum(results[i][2]));
print('{},{},{}'.format(a, b, c))
実はこれでも対策は不十分でどうにもならないことがある.子プロセスの準備中などに止められると異常終了して意図通りに止まらないことがあるのだ.(is_alive()のせいかも)