Python開発入門52 並行処理におけるスレッドとプロセスの違いを解説

Python

はじめに

プログラミングにおける並行処理は、複数のタスクを同時に実行する方法です。Pythonでは、スレッド、プロセス、非同期I/Oなどの手法を利用して並行処理を実現できます。

この記事では、Pythonで利用できる並行処理の基礎、各手法の違い、そして適切な使い分けについて詳しく解説します。

並行処理とは

並行処理と並列処理の違い

  • 並行処理(Concurrency):
    複数のタスクを切り替えながら進行させること。CPUコアが1つでも実現可能。
  • 並列処理(Parallelism):
    複数のタスクを同時に実行すること。複数のCPUコアが必要。

Pythonでは、これらを区別しながら適切な処理方法を選択することが重要です。

Pythonの並行処理の主な手法

  1. スレッド(threadingモジュール)
    軽量なスレッドを使って、同一プロセス内で複数のタスクを実行します。
  2. プロセス(multiprocessingモジュール)
    各プロセスが独立して動作し、並列処理に適しています。
  3. 非同期I/O(asyncioモジュール)
    非同期イベントループを利用して、I/Oバウンドのタスクを効率化します。

スレッドを使った並行処理

スレッドの概要

スレッドは、1つのプロセス内で独立した処理を実行する軽量な単位です。同じメモリ空間を共有するため、データのやり取りが高速ですが、競合状態(Race Condition)に注意が必要です。

スレッドの使い方

例:スレッドの基本
import threading

def print_numbers():
    for i in range(5):
        print(i)

thread = threading.Thread(target=print_numbers)
thread.start()
thread.join()

説明:

  • threading.Thread: 新しいスレッドを作成します。
  • start(): スレッドを開始します。
  • join(): スレッドの終了を待機します。

スレッドの課題

  1. グローバルインタプリタロック(GIL)
    PythonのスレッドはGILにより制限され、CPUバウンドの処理ではパフォーマンスが向上しにくい。
  2. スレッド間のデータ競合
    メモリを共有するため、データ競合を防ぐための同期が必要。

プロセスを使った並列処理

プロセスの概要

プロセスは、各プロセスが独立したメモリ空間を持ち、完全に並列で動作します。GILの影響を受けないため、CPUバウンドのタスクに適しています。

プロセスの使い方

例:プロセスの基本
from multiprocessing import Process

def print_numbers():
    for i in range(5):
        print(i)

process = Process(target=print_numbers)
process.start()
process.join()

説明:

  • multiprocessing.Process: 新しいプロセスを作成します。
  • start(): プロセスを開始します。
  • join(): プロセスの終了を待機します。

プロセスの課題

  1. メモリ使用量
    プロセスごとに独立したメモリ空間を持つため、メモリ消費が増加します。
  2. データ共有の複雑さ
    プロセス間でデータを共有する場合、QueuePipeなどの仕組みを利用する必要があります。

非同期I/Oを使った処理

非同期I/Oの概要

非同期I/Oは、I/O操作を効率化するための手法です。イベントループを活用し、待機中の時間を他のタスクに割り当てることで効率的な処理を実現します。

非同期I/Oの使い方

例:非同期関数の基本
import asyncio

async def print_numbers():
    for i in range(5):
        print(i)
        await asyncio.sleep(1)

asyncio.run(print_numbers())

説明:

  • async def: 非同期関数を定義します。
  • await: 非同期タスクを待機します。
  • asyncio.run: イベントループを実行します。

非同期I/Oの利点

  1. I/Oバウンドタスクの効率化
    ネットワーク通信やファイル操作が多いタスクに最適。
  2. シンプルなコード
    イベント駆動型のコードを直感的に記述可能。

各手法の比較と選択

特徴スレッドプロセス非同期I/O
並列性制限あり(GILの影響)完全な並列並列性はないが効率的
用途軽量タスクの実行CPUバウンドの処理I/Oバウンドの処理
メモリ使用量低い高い非常に低い
データ共有簡単(共有メモリ)複雑(Queue/Pipe)簡単(同じイベントループ)

まとめ

Pythonの並行処理は、タスクの種類に応じてスレッド、プロセス、非同期I/Oを適切に選択することで、効率的なプログラムを構築できます。この記事で解説した基本と応用を参考に、プロジェクトに最適な並行処理の方法を実装してみてください!

最後まで読んで頂きありがとうございます!

面白かった、参考になった、と少しでも感じて頂けましたら
ブログランキング上位になるための応援をして頂けないでしょうか!
今後も面白い記事を更新していきますので、ぜひ宜しくおねがいします!
Pythonプログラミング

コメント