「マルチスレッドプログラミング」のコラム

トップページ>「マルチスレッドプログラミング」のコラム

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といった注意点も存在します。これらの点を理解した上で、適切な場面でマルチスレッドを活用することで、プログラムの効率を大幅に改善することができます。最初は簡単な例から始め、徐々に複雑な処理に挑戦していくのがおすすめです。





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




< ビット演算
参照渡し >







コラム一覧

if文
for文
関数
配列
文字列
正規表現
ファイル入出力
openpyxl
Numpy
Matplotlib
Pandas
scikit-learn
seaborn
beautifulsoup
tkinter
OpenCV
pygame
メイン関数
自作ライブラリ
画像処理
機械学習
スクレイピング
データ分析
グラフ作成
API
可読性
デバッグ
例外処理
コメント
組み込み関数
flask
学び方
ビット演算
マルチスレッドプログラミング
参照渡し
pyenv
エディタ
生成AI
画像認識
Streamlit
lambda式
物理演算シミュレーション
命名規則
遺伝的アルゴリズム
関数型プログラミング
オブジェクト指向
ツリー図
Anaconda
Google Colaboratory
PyTorch
NLTK
音声処理
yt-dlp
組み込み開発
データベース操作
iclawler
PyCaret
pickle
plotly
polars
Mecab
乱数
PyInstaller
MySQL
Pip
sys.argv
データ型
secrets
MediaPipe
YOLO
ソート