【Pythonコラム】Pythonで始めるマルチスレッドプログラミング:処理を同時に進めて効率アップ!




Pythonで始めるマルチスレッドプログラミング:処理を同時に進めて効率アップ!

Pythonは、Web開発からデータ分析、機械学習まで、幅広い分野で活躍する人気のプログラミング言語です。そのPythonで、プログラムの処理速度を向上させるテクニックの一つが「マルチスレッドプログラミング」です。

なぜマルチスレッド?

プログラムは通常、上から順番に処理を実行していきます。例えば、画像を読み込んで処理し、次にネットワークからデータをダウンロードするといった処理があった場合、画像を処理している間はデータのダウンロードは待たされます。しかし、これらの処理は必ずしも順番に行う必要はなく、同時に進められる場合もあります。

ここで登場するのがマルチスレッドです。スレッドとは、プログラムを構成する実行単位のこと。マルチスレッドプログラミングでは、プログラムを複数のスレッドに分割し、これらのスレッドを並行して実行することで、処理時間を短縮できます。

特に、CPUの処理を待つ時間が長い処理(I/Oバウンド処理)に効果を発揮します。例えば、ネットワーク通信、ファイル読み書き、データベースアクセスなどが挙げられます。これらの処理を複数のスレッドに分割することで、CPUが待機している時間を有効活用し、プログラム全体のパフォーマンスを向上させることができます。

マルチスレッドの基本:threadingモジュール

Pythonでマルチスレッドプログラミングを行うには、標準ライブラリのthreadingモジュールを使用します。基本的な流れは以下の通りです。

  1. スレッドで実行する関数を定義する: スレッドに実行させたい処理を関数として定義します。
  2. threading.Threadオブジェクトを作成する: 定義した関数を引数として、threading.Threadオブジェクトを作成します。
  3. start()メソッドでスレッドを開始する: Threadオブジェクトのstart()メソッドを呼び出すと、新しいスレッドが生成され、定義した関数が実行されます。
  4. join()メソッドでスレッドの終了を待つ (オプション): メインスレッドが、作成したスレッドの終了を待つ必要がある場合、join()メソッドを使用します。

以下に簡単なサンプルコードを示します。

 import threading
 import time

 def print_numbers(name):
    for i in range(5):
        print(f"{name}: {i}")
        time.sleep(1)  # 1秒間待機 (I/Oバウンド処理の模擬)

 # スレッド1を作成
 thread1 = threading.Thread(target=print_numbers, args=("Thread-1",))

 # スレッド2を作成
 thread2 = threading.Thread(target=print_numbers, args=("Thread-2",))

 # スレッドを開始
 thread1.start()
 thread2.start()

 # スレッドの終了を待つ
 thread1.join()
 thread2.join()

 print("すべてのスレッドが終了しました。")

このコードでは、print_numbersという関数を定義し、2つのスレッドで実行しています。time.sleep(1)は、I/Oバウンド処理を模擬するためのものです。このsleepによって、CPUが待機する時間が生まれますが、複数のスレッドで並行して実行することで、全体の処理時間を短縮できます。

スレッドセーフとGIL (Global Interpreter Lock)

マルチスレッドプログラミングを行う上で注意すべき点として、「スレッドセーフ」と「GIL (Global Interpreter Lock)」があります。

  • スレッドセーフ: 複数のスレッドが共有のリソース(変数やオブジェクトなど)に同時にアクセスすると、予期せぬ結果を引き起こす可能性があります。これを避けるためには、ロックなどの排他制御の仕組みを利用して、リソースへのアクセスを同期する必要があります。
  • GIL: PythonのGILは、同時に実行できるネイティブスレッドの数を1つに制限する機構です。つまり、複数CPUコアを持つ環境でも、Pythonのスレッドは完全に並列に実行されるわけではありません。そのため、CPUバウンドな処理(計算処理など)では、マルチスレッドによるパフォーマンス向上が期待できない場合があります。

GILの影響を回避するためには、以下の方法があります。

  • マルチプロセス: multiprocessingモジュールを使用して、複数のプロセスを生成し、並行処理を行います。プロセスはそれぞれ独立したメモリ空間を持つため、GILの影響を受けません。
  • C拡張: CPUバウンドな処理をC言語などで実装し、Pythonから呼び出すことで、GILの影響を回避できます。

まとめ

Pythonのマルチスレッドプログラミングは、I/Oバウンドな処理のパフォーマンスを向上させる有効な手段です。しかし、スレッドセーフやGILといった注意点も存在します。これらの点を理解した上で、適切な場面でマルチスレッドを活用することで、プログラムの効率を大幅に改善することができます。最初は簡単な例から始め、徐々に複雑な処理に挑戦していくのがおすすめです。



< ビット演算
コラム一覧に戻る
参照渡し >

レッスン概要

◯月額4,000円で質問し放題!!
◯完全オンライン
◯翌日までには必ず返信
◯挫折しない独自の学習メソッド
◯圧倒的高評価!!
◯テキストベースで時間を選ばない
◯高品質なサンプルコード
詳細はこちら
興味がある方はまず質問だけでもどうぞ!