Pythonのmultiprocessingモジュール完全ガイド【並列処理でパフォーマンス最大化】

Pythonのmultiprocessingモジュール:並列処理の徹底ガイド【戻り値・共有メモリ・Pipeまで実例付き】

Pythonのmultiprocessingモジュール:並列処理の徹底ガイド【実例付き】

Python multiprocessing を使うと、マルチコアCPUを活かしてプログラムを高速化できます。
本記事では、基本的な使い方から、戻り値の扱い、for文でのプロセス起動、共有メモリ(Value / Array)、Pipeによる通信、Windowsでの注意点、threadingとの違いまでをまとめて解説します。

multiprocessingモジュールの基本【Python multiprocessing 使い方の全体像】

Pythonのmultiprocessingモジュールは、「プロセス単位」で並列処理を行うための標準ライブラリです。
threadingと違い、GIL(Global Interpreter Lock)の制約を受けず、CPUバウンドな処理の高速化に向いています。

  • GILの制約を回避し、真の並列処理を実現
  • プロセス間でデータを共有する手段(共有メモリ、Queue、Pipe、Managerなど)を提供
  • CPUバウンドのタスク(大量計算、画像処理、機械学習前処理など)に最適

Python multiprocessing 使い方」を理解するために、まずは最低限の構成から見ていきます。

Python multiprocessingの基本的な使い方

例1: 最もシンプルなプロセス生成

from multiprocessing import Process

def worker():
    print("ワーカーが実行されています!")

if __name__ == "__main__":
    p = Process(target=worker)
    p.start()   # プロセス開始
    p.join()    # 終了待ち

この例が Python multiprocessing 使い方 の最小構成です。
Windows環境では特に、必ず if __name__ == "__main__": の中でプロセスを生成する必要があります(後述)。

例2: Python multiprocessing for文で複数プロセスを起動

複数のプロセスを起動したい場合、「Python multiprocessing for文」で繰り返し起動するのが定番です。

from multiprocessing import Process
import time

def worker(num):
    print(f"プロセス {num} 開始")
    time.sleep(1)
    print(f"プロセス {num} 終了")

if __name__ == "__main__":
    processes = []
    for i in range(5):  # for文で複数プロセスを生成
        p = Process(target=worker, args=(i,))
        processes.append(p)
        p.start()

    for p in processes:
        p.join()

このように、forループでプロセスをまとめて起動し、後半のループでjoin()するのが典型パターンです。

例3: プロセスプールで戻り値をまとめて取得(Pool.map)

Python multiprocessing 戻り値」を簡単に扱うなら、Poolを使った方法が最もわかりやすいです。

from multiprocessing import Pool

def square(n):
    return n * n

if __name__ == "__main__":
    with Pool(4) as p:
        # Python multiprocessing 戻り値 をリストで受け取る
        results = p.map(square, [1, 2, 3, 4, 5])
        print(results)  # [1, 4, 9, 16, 25]

Pool.mapは、「引数リスト」を受け取り、「戻り値のリスト」を順番通りに返してくれるため、戻り値を扱う定番パターンです。

Python multiprocessing 戻り値の受け取り方まとめ

Python multiprocessing 戻り値 を扱う方法はいくつかあります。代表的なのは次の3つです。

  1. Pool.map / Pool.starmap でリストとして受け取る
  2. apply_async で非同期に受け取り、get()で取得
  3. QueueManager.list など共有オブジェクトに書き込む

1. Pool.starmapで複数引数+戻り値

from multiprocessing import Pool

def add(a, b):
    return a + b

if __name__ == "__main__":
    args = [(1, 2), (3, 4), (5, 6)]
    with Pool(3) as p:
        results = p.starmap(add, args)
    print(results)  # [3, 7, 11]

2. apply_asyncを使った非同期な戻り値取得

from multiprocessing import Pool
import time

def compute(x):
    time.sleep(1)
    return x * x

if __name__ == "__main__":
    with Pool(4) as p:
        async_result = p.apply_async(compute, (10,))
        # 他の処理をここで行える
        result = async_result.get()  # 戻り値を取得
        print(result)  # 100

3. Queueを使って戻り値を集める

from multiprocessing import Process, Queue

def worker(x, q):
    q.put(x * x)  # 戻り値をQueueへ

if __name__ == "__main__":
    q = Queue()
    processes = [Process(target=worker, args=(i, q)) for i in range(5)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()

    results = [q.get() for _ in range(5)]
    print(results)

複数プロセスからの結果を逐次集めたいときは、Queueも便利です。

Python multiprocessing 共有メモリの基本

プロセスは通常、メモリ空間を共有しませんが、Python multiprocessing 共有メモリとして ValueArrayを使うことで、特定の値を共有できます。

Python multiprocessing Valueで単一値を共有

from multiprocessing import Value, Process

def increment(shared_value):
    for _ in range(1000):
        shared_value.value += 1

if __name__ == "__main__":
    # 'i' は C のint型(整数)を表す typecode
    counter = Value('i', 0)  # 初期値0

    processes = [Process(target=increment, args=(counter,)) for _ in range(4)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()

    print("最終カウント:", counter.value)

このように Python multiprocessing Value を使うと、複数プロセス間で1つの整数値などを共有できます。
実際には競合を防ぐためにLockを組み合わせることも多いです。

Arrayで配列を共有する

from multiprocessing import Process, Array

def worker(shared_arr):
    for i in range(len(shared_arr)):
        shared_arr[i] *= 2

if __name__ == "__main__":
    arr = Array('i', [1, 2, 3, 4])
    p = Process(target=worker, args=(arr,))
    p.start()
    p.join()
    print(list(arr))  # [2, 4, 6, 8]

Managerを使った高レベルな共有オブジェクト

from multiprocessing import Process, Manager

def worker(shared_list, value):
    shared_list.append(value)

if __name__ == "__main__":
    with Manager() as manager:
        shared_list = manager.list()
        processes = [Process(target=worker, args=(shared_list, i)) for i in range(5)]
        for p in processes:
            p.start()
        for p in processes:
            p.join()
        print(list(shared_list))  # [0,1,2,3,4](順序は保証されない場合あり)

Managerはリストや辞書といった高レベルオブジェクトを共有したい場合に便利です。

Python multiprocessing PipeとQueueでのプロセス間通信

プロセス間でデータをやり取りするには、QueueだけでなくPython multiprocessing Pipeもよく使われます。

Python multiprocessing Pipeの基本例

from multiprocessing import Process, Pipe

def sender(conn):
    conn.send("子プロセスからのメッセージ")
    conn.close()

if __name__ == "__main__":
    parent_conn, child_conn = Pipe()
    p = Process(target=sender, args=(child_conn,))
    p.start()

    msg = parent_conn.recv()  # Pipeから受信
    print(msg)
    p.join()

Pipe()は2つの接続端点(parent_conn / child_conn)を返し、一方向・双方向の通信に利用できます。

Queueとの使い分け

  • 複数プロセスが同じキューにデータを流したい → Queueが向いている
  • 1対1の通信でシンプルにやり取りしたい → Pipeがシンプル

multiprocessingの実務的な活用例

例1: 大量データを並列処理

from multiprocessing import Pool
import time

def compute(x):
    time.sleep(1)  # 重い計算の代わり
    return x * x

if __name__ == "__main__":
    with Pool(4) as p:
        results = p.map(compute, range(10))
        print(results)

例2: キューを利用したプロセス間通信

from multiprocessing import Process, Queue

def worker(q):
    q.put("データ送信")

if __name__ == "__main__":
    q = Queue()
    p = Process(target=worker, args=(q,))
    p.start()
    print(q.get())
    p.join()

例3: 並列Webスクレイピング

from multiprocessing import Pool
import requests

def fetch_url(url):
    response = requests.get(url)
    return url, response.status_code

if __name__ == "__main__":
    urls = ["https://example.com" for _ in range(5)]
    with Pool(5) as p:
        results = p.map(fetch_url, urls)
        print(results)

例4: 画像処理の並列化

from multiprocessing import Pool
from PIL import Image

def process_image(image_path):
    img = Image.open(image_path)
    img = img.convert("L")
    img.save("processed_" + image_path)

if __name__ == "__main__":
    image_files = ["image1.jpg", "image2.jpg", "image3.jpg"]
    with Pool(3) as p:
        p.map(process_image, image_files)

例5: データベースクエリの並列実行

from multiprocessing import Pool
import sqlite3

def fetch_data(query):
    conn = sqlite3.connect("example.db")
    cursor = conn.cursor()
    cursor.execute(query)
    result = cursor.fetchall()
    conn.close()
    return result

if __name__ == "__main__":
    queries = ["SELECT * FROM users", "SELECT * FROM orders"]
    with Pool(2) as p:
        results = p.map(fetch_data, queries)
        print(results)

Python multiprocessing Windows環境での注意点

Python multiprocessing Windows」でよくつまずくポイントは、プロセスの生成方法です。Windowsではプロセス生成方式が spawn のため、 if __name__ == "__main__": ブロックの外でプロセスを生成すると無限ループのような挙動になることがあります。

  • 必ず if __name__ == "__main__": の中でプロセス・Poolを生成する
  • PyInstallerなどでEXE化する場合は freeze_support() が必要になるケースがある
  • Jupyter環境ではうまく動かないことがあるので、.pyスクリプトで実行するのが安全
from multiprocessing import Process, freeze_support

def worker():
    print("Windowsでも安全に実行")

if __name__ == "__main__":
    freeze_support()  # EXE化時などに必要になる場合がある
    p = Process(target=worker)
    p.start()
    p.join()

Python multiprocessing threadingとの違いと使い分け

Python multiprocessing threading どっちを使うべきか?」はよくある疑問です。

multiprocessingが向いているケース

  • CPUバウンドな処理(数値計算、画像処理、機械学習前処理など)
  • GILの影響を避けて高速化したいとき

threadingが向いているケース

  • I/Oバウンドな処理(ネットワーク通信、ファイル読み書き、API呼び出し)
  • 軽量でシンプルに並行処理したいとき

ざっくり言うと、CPUをガンガン使うならmultiprocessing、I/O待ちが多いならthreadingというイメージで選ぶと失敗しにくくなります。

次に読むべき記事

まとめ:Python multiprocessingでCPUをフル活用しよう

本記事では、Python multiprocessing 使い方を軸に、for文でのプロセス起動、戻り値の受け取り方、 共有メモリ(Value・Array・Manager)Pipe/Queueによる通信Windows環境での注意点、 そしてthreadingとの違いまでを解説しました。

まずはこの記事のサンプルコードを手元で動かしてみて、「単一プロセスのコードを、multiprocessingに書き換えるとどう変わるか?」を体感してみるのがおすすめです。

さらにPython全体を体系的に学びたい方はこちら:

Python完全ガイドを見る

© 2025 Pythonガイド - すべての権利を保有

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です