Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Python辞典

  1. トップページ
  2. Python辞典
  3. multiprocessing.Process()

multiprocessing.Process()

『multiprocessing』モジュールは複数のプロセスを使って処理を並列実行するための標準ライブラリです。各プロセスは独立したメモリ空間を持ち、PythonのGIL(グローバルインタープリタロック)の制約を受けないため、CPUを多用する計算処理を複数のCPUコアに分散して高速化できます。プロセス間のメモリは共有されないため、データのやり取りはQueueやPipeなどを通じて行います

構文
from multiprocessing import Process, Pool, Queue

# プロセスの生成と実行
p = Process(target=関数, args=(引数,))
p.start()
p.join()

# プロセスプール(複数プロセスで並列処理)
with Pool(processes=プロセス数) as pool:
    results = pool.map(関数, イテラブル)

# プロセス間通信(Queue)
q = Queue()
q.put(データ)
data = q.get()
クラス・メソッド一覧
クラス・メソッド概要
Process(target, args)子プロセスオブジェクトを生成する。
p.start()子プロセスを開始する。
p.join()子プロセスの終了を待つ。
p.terminate()プロセスを強制終了する。
Pool(processes=N)N個のワーカープロセスのプールを生成する。
pool.map(func, iter)iterの各要素にfuncを並列適用してリストで返す。
pool.starmap(func, iter)各要素をアンパックしてfuncに渡す(複数引数対応)。
pool.apply_async(func, args)非同期でfuncを実行しAsyncResultを返す。
Queue()プロセス間でデータをやり取りするためのキューを生成する。
q.put(item)キューにデータを追加する。
q.get()キューからデータを取り出す(なければブロック)。
サンプルコード
from multiprocessing import Process, Pool, Queue
import os
import time

# Processの基本使用
def worker(name, duration):
    print(f"[{name}] プロセスID: {os.getpid()}, 処理開始")
    time.sleep(duration)
    print(f"[{name}] 処理完了")

if __name__ == '__main__':
    processes = []
    for i in range(3):
        p = Process(target=worker, args=(f"Worker-{i}", 1))
        processes.append(p)
        p.start()

    for p in processes:
        p.join()
    print("すべてのプロセスが完了")

# Pool.map: CPU密集処理の並列化
def cpu_task(n):
    """素数判定(重い計算のシミュレーション)"""
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

if __name__ == '__main__':
    numbers = list(range(10000, 10100))

    # 逐次処理
    start = time.time()
    result1 = [cpu_task(n) for n in numbers]
    print(f"逐次処理: {time.time() - start:.3f}秒")

    # 並列処理(4プロセス)
    start = time.time()
    with Pool(processes=4) as pool:
        result2 = pool.map(cpu_task, numbers)
    print(f"並列処理: {time.time() - start:.3f}秒")

# Queue: プロセス間でデータをやり取り
def producer(q):
    for i in range(5):
        q.put(i * i)
        time.sleep(0.1)
    q.put(None)     # 終了シグナル

def consumer(q):
    while True:
        item = q.get()
        if item is None:
            break
        print(f"受信: {item}")

if __name__ == '__main__':
    q  = Queue()
    p1 = Process(target=producer, args=(q,))
    p2 = Process(target=consumer, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
概要

multiprocessingを使う場合は、スクリプトのメインコードを必ず『if __name__ == \'__main__\':』の中に書く必要があります。Windowsではプロセスをforkではなくspawnで生成するため、子プロセスがスクリプトをインポートして無限ループになるのを防ぐためです。

プロセス間のメモリは共有されないため、グローバル変数を子プロセスで変更しても親プロセスには反映されません。データのやり取りには『Queue』(キュー)・『Pipe』(パイプ)・『Manager』(共有メモリ)などを使います。

プロセスの起動にはスレッドより大きなオーバーヘッドがあります。少量のデータや短い処理では逐次処理より遅くなる場合もあるため、実際に計測して効果を確認しましょう。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。