スレッド
Thread
スレッドは、プロセスの中で命令を実行する処理の流れ・実行単位です。1プロセスに一つだけの場合も、複数の場合もあります。複数のスレッドがあることと、同じ瞬間に並列実行されることは区別します。
🐾 猫で例えると?
アメショへ前足と後ろ足を向ける茶トラ。1つの体を共有しながら、手と足が別々の動きを受け持つ、と見立てるとスレッドを想像できます。実行中のプログラムのまとまりがプロセス、その中の処理の流れがスレッドです。同じプロセスのスレッドはメモリなどを共有しますが、実際に同じ瞬間に動くかはCPUや実行環境によります。
💻 プログラミングにおける「スレッド」とは?
コンピュータにおける「プロセス」が、OSから独立したメモリ空間を割り当てられた大きな実行プログラム(例:ブラウザ、ゲームアプリなど)であるのに対し、「スレッド」はそのプロセスの中でさらに細かく分かれた、実際の作業員のような存在です。
アプリでは、画面の応答と時間のかかる処理を別の実行経路に分けることがあります。ただし、現代のブラウザは複数プロセスと複数スレッドを組み合わせるため、「ブラウザ全体が1プロセスで、操作ごとに1スレッド」と決まっているわけではありません。
⚠️ スレッドの仕組みとマルチスレッドのメリット
同じプロセスのスレッドはアドレス空間などを共有しつつ、各自のスタックや実行位置を持ちます。共有しやすい反面、同じデータの同時更新には同期が必要です。スレッドを増やすことと、処理が実際に並列に速く進むことも別です。
Pythonによるマルチスレッドの例
以下はPythonの threading で、待ち時間のある2つの仕事を並行に進める例です。sleep はCPUを使う重い計算ではなく待機です。実行開始はOSのスケジューリングに従うため、完全に同じ瞬間とは限りません。
# Pythonでのマルチスレッドの実装例
import threading
import time
def cat_action(name):
print(f"{name}処理を開始ニャ")
time.sleep(2) # 重い処理を想定(2秒待機)
print(f"{name}処理が完了ニャ")
# 2つの処理(スレッド)を生成
thread_hand = threading.Thread(target=cat_action, args=("手でのツッコミ",))
thread_foot = threading.Thread(target=cat_action, args=("足でのツッコミ",))
# 2つのスレッドを同時にスタート(並行処理)
thread_hand.start()
thread_foot.start()
# 両方のスレッドが終わるのを待つ
thread_hand.join()
thread_foot.join()
print("すべてのツッコミが終了!") この例では待ち時間を重ねられます。通常のGILを有効にしたCPythonでは、PythonのCPU計算をスレッドに分けても、同時実行による高速化が得られない場合があります。CPU計算にはプロセス分割などを比較し、使っている実装・ビルドの制約を確認します。
🛠️ スレッドを賢く使うためのポイント
マルチスレッドは非常に強力ですが、複数の作業員が「同じお皿(共有メモリ)」を同時に触るため、プログラムのバグを生み出しやすいというIT現場ならではの注意点があります。
- レースコンディション(競合状態): 2つのスレッドが同時に同じデータを書き換えようとした結果、データがぐちゃぐちゃになってしまう現象。猫が1つのお皿のごはんを奪い合って散らかすようなものです。これを防ぐために「Mutex(ミューテックス)」や「ロック」という仕組みで排他制御を行います。
- デッドロックの回避: スレッドAがリソース1を確保してリソース2を待っており、スレッドBがリソース2を確保してリソース1を待っている、というようにお互いが身動きを取れなくなるエラー。2匹の猫が互いのしっぽを噛み合ってフリーズしてしまう状態に似ています。
- ブラウザーでの処理の使い分け: ブラウザーのメインスレッドではJavaScriptの処理を順に実行します。通信などの待ち時間は非同期処理で扱い、重い計算を別スレッドへ分けたい場合はWeb Workersを使います。非同期にしただけで計算が別スレッドへ移るわけではありません。
1匹の猫が手足を動かすように、1つのプロセスでも複数の仕事を進められます。共有するデータがある場合は、どのスレッドがいつ更新するかを整理しましょう。処理を分けることと、同時に触っても結果が正しくなることは別の設計です。