Pythonでプロセスを使う(multiprocessing)
この記事では、Pythonの`multiprocessing`モジュールを使って並列処理を行う方法を説明します。複数のCPUコアを効果的に活用し、プログラムの処理速度を向上させるための様々な手法を紹介します。
目次
- プロセスとは?
- multiprocessingモジュールの基本
- プロセス間通信
- Processクラスによるプロセス生成
- Poolクラスによるプロセスプール
- Queueクラスによるプロセス間データ共有
- ロックによる排他制御
- マネージャーによる共有データ管理
- 例外処理
プロセスとは?
プログラムの実行単位。OSは複数のプロセスを同時に実行することで並列処理を実現します。Pythonでは、`multiprocessing`モジュールを使用することで、複数のプロセスを生成し、並列処理を行うことができます。
マルチプロセスは、マルチスレッドと異なり、各プロセスは独立したメモリ空間を持つため、グローバル変数の共有による問題が発生しません。ただし、プロセス間の通信には工夫が必要です。
multiprocessingモジュールの基本
Pythonの`multiprocessing`モジュールは、マルチプロセスプログラミングを簡素化するための様々な機能を提供します。代表的なクラスとして、`Process`、`Pool`、`Queue`、`Lock`などがあります。
プロセス間通信
プロセス間でデータのやり取りを行うには、`Queue`、`Pipe`、`Manager`などの機構を利用します。`Queue`は、複数のプロセス間でデータの送受信を行うためのキューを提供します。`Pipe`は、2つのプロセス間で双方向の通信を行うためのパイプを提供します。`Manager`は、共有メモリを用いてプロセス間でデータ共有を行うための機能を提供します。
Processクラスによるプロセス生成
`Process`クラスは、新しいプロセスを生成するためのクラスです。`target`引数には実行する関数を、`args`引数には関数の引数を指定します。
import multiprocessing
def worker(num):
print(f'Worker {num}: {num * 2}')
if __name__ == '__main__':
processes = []
for i in range(5):
p = multiprocessing.Process(target=worker, args=(i,))
processes.append(p)
p.start()
for p in processes:
p.join()
Poolクラスによるプロセスプール
`Pool`クラスは、複数のプロセスをプールとして管理し、タスクを効率的に処理するためのクラスです。`map`メソッドを用いることで、複数のデータに対して関数を並列実行することができます。
import multiprocessing
def worker(num):
return num * 2
if __name__ == '__main__':
with multiprocessing.Pool(processes=5) as pool:
results = pool.map(worker, range(10))
print(results)
Queueクラスによるプロセス間データ共有
`Queue`クラスは、プロセス間でデータの送受信を行うためのキューを提供します。`put`メソッドでデータを追加し、`get`メソッドでデータを取得します。
import multiprocessing
def producer(queue):
for i in range(5):
queue.put(i)
def consumer(queue):
while True:
try:
item = queue.get()
print(f'Consumed: {item}')
except queue.Empty:
break
if __name__ == '__main__':
queue = multiprocessing.Queue()
producer_process = multiprocessing.Process(target=producer, args=(queue,))
consumer_process = multiprocessing.Process(target=consumer, args=(queue,))
producer_process.start()
consumer_process.start()
producer_process.join()
consumer_process.join()
ロックによる排他制御
複数のプロセスが共有資源に同時にアクセスすると、データの破損が発生する可能性があります。`Lock`クラスは、排他制御を行うためのロックを提供します。`acquire`メソッドでロックを取得し、`release`メソッドでロックを解放します。
マネージャーによる共有データ管理
`multiprocessing.Manager`を使うと、プロセス間で安全に共有できるオブジェクトを作成できます。これにより、`Queue`や`Lock`をより簡単に使用できるようになります。
例外処理
マルチプロセス処理では、例外処理が重要になります。`try...except`ブロックを使用して、予期しないエラーが発生した場合に適切に処理を行う必要があります。
関連記事
- Pythonでスレッドを使う(threading)
- Pythonでスレッドプール・プロセスプールを使う(concurrent.futures)
- Pythonでスレッド間・プロセス間通信
- PythonでGIL(グローバルインタプリタロック)を理解する
- Pythonで外部コマンドを実行(os.system, subprocess)
- Pythonで非同期処理を使う(asyncio, Python 3.5以降)
- Pythonでコルーチンを使う(asyncio, Python 3.5以降)
- PythonでFuture・Taskを使う(asyncio, Python 3.5以降)
- Pythonでaiohttpを使って非同期HTTPリクエストを送信 (Python 3.5以降)
- Pythonでシグナルを捕捉