multiprocessing#
multiprocessing パッケージは、ローカルとリモート両方の並行処理を提供します。また、このパッケージはスレッドの代わりにサブプロセスを使用することにより、グローバルインタープリタロック の問題を避ける工夫が行われています。
from multiprocessing import Process
if __name__ == "__main__":
p1 = Process(name="プロセス名", target=実行する関数, args=(関数の引数,))
Warnig
if name == 'main':
がないとエラーとなります。
Process クラス#
multiprocessing モジュールでは、はじめに Process のオブジェクトを作成し、続いて start() メソッドを呼び出します。
from multiprocessing import Process
def f(name):
print('hello', name)
if __name__ == '__main__':
p = Process(target=f, args=('bob',))
p.start()
p.join()
プロセス間での状態の共有#
プロセス間のデータ共有が必要な場合のために multiprocessing モジュールには2つの方法が用意されている。
共有メモリ (Shared memory)#
データを共有メモリ上に保持するために Value クラス、もしくは Array クラスが用意されている。
from multiprocessing import Process, Value, Array
def f(n, a):
n.value = 3.1415927
for i in range(len(a)):
a[i] = -a[i]
if __name__ == '__main__':
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target=f, args=(num, arr))
p.start()
p.join()
print(num.value)
# 3.1415927
print(arr[:])
# [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
num と arr を生成するときに使用されている、引数 'd' と 'i' は array モジュールにより使用される種別の型コードです。 ここで使用されている 'd' は倍精度浮動小数、 'i' は符号付整数を表します。これらの共有オブジェクトは、プロセスセーフでありスレッドセーフです。
サーバープロセス (Server process)#
Manager() 関数により生成されたマネージャーオブジェクトはサーバープロセスを管理します。 マネージャーオブジェクトは Python のオブジェクトを保持して、 他のプロセスがプロキシ経由でその Python オブジェクトを操作することができます。
Manager() 関数が返すマネージャは list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value, Array を サポートします。 以下にサンプルコードを示します。
from multiprocessing import Process, Manager
def f(d, l):
d[1] = '1'
d['2'] = 2
d[0.25] = None
l.reverse()
if __name__ == '__main__':
with Manager() as manager:
d = manager.dict()
l = manager.list(range(10))
p = Process(target=f, args=(d, l))
p.start()
p.join()
print(d)
print(l)
戻り値#
Python 3では、multiprocessingモジュールを使用してマルチプロセス処理を実行することができます。マルチプロセス処理によって、並列処理による高速化が可能になります。
マルチプロセスで戻り値を取得するには、multiprocessingモジュールのProcessクラスを使用します。以下は、戻り値を取得するための簡単な例です。
from multiprocessing import Process, Queue
def worker(queue):
result = "This is the result"
queue.put(result)
if __name__ == '__main__':
queue = Queue()
p = Process(target=worker, args=(queue,))
p.start()
p.join()
result = queue.get()
print(result)
この例では、worker関数が新しいプロセスで実行されます。worker関数は、Queueオブジェクトを受け取り、結果をQueueに入れます。 親プロセスは、子プロセスを開始し、終了するまで待機し、Queueから結果を取得して表示します。
注意すべき重要な点として、上記のコードはif name == 'main':以下に置かれています。 これは、マルチプロセス処理を行う場合に必要なもので、Windowsなどの環境で実行する場合は必要になることがあります。