multiprocessing
multiprocessing とは、プロセスベースで並列処理を行う python の bulid-in モジュールです。
処理を並列に行えるので、処理が速くなります。
multiprocessing — プロセスベースの並列処理
同じく並列処理を行うモジュールに、threading という bulit-in モジュールもあります。
プロセスとスレッドの違いは以下を参照しました。
Windows OS入門:第3回 プロセスとスレッド (1/2)
まず、私のざっくりとした理解では以下の感じです。
プロセス
プログラムの実行単位。複数のスレッドで一つのプロセスになる。
スレッド
プロセスをより細かい実行単位に分割したもの。プロセス内で複数のスレッドは、リソース(例えば変数)を共有する。
マルチプロセス
プロセスを複数コピーして、並列で実行する。それぞれのプロセスは別なので、リソースは共有されない。
マルチスレッド
一つのプロセス内で、スレッドを複数コピーして、並列で実行する。スレッドはリソースを共有できる。
GIL グローバルインタプリタロック
また、multiporcessing とmultitheading どちらを使うべきかという話では、GIL グローバルインタプリタロック という言葉が良く出てきます。
GIL とは、実行時に一つだけ thread を実行する仕組みのことです。
グローバルインタプリタロック(英: Global Interpreter Lock, GIL)とは、プログラミング言語のインタプリタのスレッドによって保持されるスレッドセーフでないコードを、他のスレッドと共有してしまうことを防ぐための排他 ロックである。インタプリタのひとつのプロセスごとに必ずひとつの GIL が存在する。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
Python は、GIL を採用しているため、multithread の取扱いが難しくなっています。
そのため、性能が十分な環境であれば、基本的に、multiprocessing を使ったほうが良いようです。
multiprocessingを試す
まずは、multiprocessingを行うための関数を作成します。
引数を3乗する関数にして、普通に実行してみます。
def cube (num):
result = num ** 3
print(result)
if __name__ == '__main__':
for num in range(10):
cube(num)
# 実行結果
# 0
# 1
# 8
# 27
# 64
# 125
# 216
# 343
# 512
# 729
想定通りの結果になっています。
同じ処理を、multiprocessing で実行するためコードを書き換えます。
multiprocessing モジュールは、まずは Process のオブジェクトを作成して、続いて start() メソッドを呼び出すことで実行できます。
Process は引数として、 「target 実行する関数」 と 「args その関数の引数(タプルで書く)」 を持ちます。
import multiprocessing
def cube (num):
result = num ** 3
print(result)
if __name__ == '__main__':
for num in range(10):
cube(num)
print('---multiprocessing---')
for num in range(10):
process = multiprocessing.Process(target=cube, args=(num, ))
process.start()
# 実行結果
# 0
# 1
# 8
# 27
# 64
# 125
# 216
# 343
# 512
# 729
# ---multiprocessing---
# 1
# 0
# 8
# 64
# 216
# 27
# 343
# 729
# 512
# 125
multiprocessing では、複数のプロセスを並列して実行するので、処理の終了順序がバラバラになっています。
プロセスIDを取得
bulid-in モジュールの os の getppid() というメソッドで、プロセスIDを取得、確認します。
import multiprocessing
import os
def cube (num):
result = num ** 3
pid = os.getpid()
print(f"process ID: {pid} result: {result}")
if __name__ == '__main__':
for num in range(10):
cube(num)
print('---multiprocessing---')
for num in range(10):
process = multiprocessing.Process(target=cube, args=(num, ))
process.start()
# 実行結果
# process ID: 4944 result: 0
# process ID: 4944 result: 1
# process ID: 4944 result: 8
# process ID: 4944 result: 27
# process ID: 4944 result: 64
# process ID: 4944 result: 125
# process ID: 4944 result: 216
# process ID: 4944 result: 343
# process ID: 4944 result: 512
# process ID: 4944 result: 729
# ---multiprocessing---
# process ID: 16828 result: 0
# process ID: 17980 result: 8
# process ID: 12088 result: 27
# process ID: 20172 result: 1
# process ID: 15368 result: 125
# process ID: 17012 result: 512
# process ID: 624 result: 64
# process ID: 18312 result: 216
# process ID: 1520 result: 343
# process ID: 18388 result: 729
singleprocessing では同じプロセスIDとなっており、multiprocessing では、プロセスIDがそれぞれ異なっています。
process の名前の取得
multiprocessing の Processオブジェクトは、それぞれを識別する名前を持ち、name という属性でアクセスできます。
また、 multiprocessing.current_process() で、現在のプロセスにアクセスすることができます。
multiprocessing.current_process()
multiprocessing.current_process().name により、 プロセスIDではなく、プロセスの名前で、それぞれのプロセスを識別してみます。
import multiprocessing
def cube (num):
result = num ** 3
name = multiprocessing.current_process().name
print(f"process name: {name} result: {result}")
if __name__ == '__main__':
for num in range(10):
cube(num)
print('---multiprocessing---')
for num in range(10):
process = multiprocessing.Process(target=cube, args=(num, ))
process.start()
# 実行結果
# process name: MainProcess result: 0
# process name: MainProcess result: 1
# process name: MainProcess result: 8
# process name: MainProcess result: 27
# process name: MainProcess result: 64
# process name: MainProcess result: 125
# process name: MainProcess result: 216
# process name: MainProcess result: 343
# process name: MainProcess result: 512
# process name: MainProcess result: 729
# ---multiprocessing---
# process name: Process-1 result: 0
# process name: Process-4 result: 27
# process name: Process-2 result: 1
# process name: Process-3 result: 8
# process name: Process-7 result: 216
# process name: Process-6 result: 125
# process name: Process-8 result: 343
# process name: Process-10 result: 729
# process name: Process-5 result: 64
# process name: Process-9 result: 512
プロセスの名前が singleprocessing ではMainProcess、multiprocessing ではそれぞれ異なる名前になっています。
以下の記事に続きます。