Pythonで始めるマルチスレッドプログラミング:処理を同時に進めて効率アップ!
Pythonは、Web開発からデータ分析、機械学習まで、幅広い分野で活躍する人気のプログラミング言語です。そのPythonで、プログラムの処理速度を向上させるテクニックの一つが「マルチスレッドプログラミング」です。
なぜマルチスレッド?
プログラムは通常、上から順番に処理を実行していきます。例えば、画像を読み込んで処理し、次にネットワークからデータをダウンロードするといった処理があった場合、画像を処理している間はデータのダウンロードは待たされます。しかし、これらの処理は必ずしも順番に行う必要はなく、同時に進められる場合もあります。
ここで登場するのがマルチスレッドです。スレッドとは、プログラムを構成する実行単位のこと。マルチスレッドプログラミングでは、プログラムを複数のスレッドに分割し、これらのスレッドを並行して実行することで、処理時間を短縮できます。
特に、CPUの処理を待つ時間が長い処理(I/Oバウンド処理)に効果を発揮します。例えば、ネットワーク通信、ファイル読み書き、データベースアクセスなどが挙げられます。これらの処理を複数のスレッドに分割することで、CPUが待機している時間を有効活用し、プログラム全体のパフォーマンスを向上させることができます。
マルチスレッドの基本:threading
モジュール
Pythonでマルチスレッドプログラミングを行うには、標準ライブラリのthreading
モジュールを使用します。基本的な流れは以下の通りです。
- スレッドで実行する関数を定義する: スレッドに実行させたい処理を関数として定義します。
threading.Thread
オブジェクトを作成する: 定義した関数を引数として、threading.Thread
オブジェクトを作成します。start()
メソッドでスレッドを開始する:Thread
オブジェクトのstart()
メソッドを呼び出すと、新しいスレッドが生成され、定義した関数が実行されます。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といった注意点も存在します。これらの点を理解した上で、適切な場面でマルチスレッドを活用することで、プログラムの効率を大幅に改善することができます。最初は簡単な例から始め、徐々に複雑な処理に挑戦していくのがおすすめです。
コラム一覧
◯for文
◯関数
◯配列
◯文字列
◯正規表現
◯ファイル入出力
◯openpyxl
◯Numpy
◯Matplotlib
◯Pandas
◯scikit-learn
◯seaborn
◯beautifulsoup
◯tkinter
◯OpenCV
◯pygame
◯メイン関数
◯自作ライブラリ
◯画像処理
◯機械学習
◯スクレイピング
◯データ分析
◯グラフ作成
◯API
◯可読性
◯デバッグ
◯例外処理
◯コメント
◯組み込み関数
◯flask
◯学び方
◯ビット演算
◯マルチスレッドプログラミング
◯参照渡し
◯pyenv
◯エディタ
◯生成AI
◯画像認識
◯Streamlit
◯lambda式
◯物理演算シミュレーション
◯命名規則
◯遺伝的アルゴリズム
◯関数型プログラミング
◯オブジェクト指向
◯ツリー図