メインコンテンツへスキップ

⚔️スレッドと非同期処理の違いを理解する

🟢 はじめに

Pythonでは「複数の処理を並行して進める」ための手段として、

  • threading を使った スレッド処理

  • asyncio を使った 非同期処理(async/await)
    の2つが存在する。

このノートでは、「どちらも並行して処理できるのに、何が違うのか? どちらをいつ使うべきか?」という点を直感的かつ具体的に整理する。


🧵threading:物理的に“分身”して動くイメージ

✅ 特徴

  • スレッドごとに実行の流れ(スタック)を持つ

  • 複数のスレッドが同時に本当に動いているように見える

  • CPUバウンド/IOバウンド問わず使えるが、GILの影響でCPUバウンドには弱い(後述)。

🧠たとえ:何人もの作業員を雇う

  • シェフが何人もいて、同時に異なる作業を進められる

  • ただし、厨房が狭い(GIL)ので、本当に同時には動けない瞬間もある。


⏳asyncio:1人が効率よく“切り替えながら”動くイメージ

✅ 特徴

  • 実際には1つのスレッドで処理をしており、待ち時間(I/Oなど)をうまく活用して切り替えて動いている

  • 処理の中に await を入れることで、「ここは他の処理に切り替えてOK」という中断点を明示する。

  • IOバウンド処理に特化。CPUバウンドな重い処理には向いていない。

🧠たとえ:1人のマルチタスク職人

  • シェフは1人だけだが、

    • オーブンで焼き始めたらすぐ冷蔵庫の準備に移り、

    • そのあと注文票を読みつつ、次の工程へ。

  • 待っている時間に別の作業を差し込むことで、1人でも効率がよい


🆚 スレッド vs 非同期処理:比較表

比較項目 threading(スレッド) asyncio(非同期)
並行の仕組み 分身(複数スレッド) 1人で切り替え(イベントループ)
並行実行できるか? ✅ 実際に複数スレッドで動く ✅ ただし「同時」ではなく「切り替え」
I/O待ちへの強さ ✅ 強い ✅ 非常に強い(本領発揮)
重たい計算処理 ❌ GILの制限により真の並列にならない(複数プロセスが必要) ❌ 1スレッドなので向いていない
コードの書きやすさ シンプルだが同期・排他制御が必要 慣れが必要だが設計が綺麗(状態管理しやすい)
UIとの親和性 △ GUIで使うときは注意が必要(メインスレッド制御) ❌ GUIとは直接相性が良くない
適している場面 マルチスレッドで定期実行・UI処理・並列クローリングなど 非同期HTTP、ファイルI/O、リアクティブWebなど

🧠GILとは?

Python(CPython)には「GIL(Global Interpreter Lock)」があり、

  • 同時に複数スレッドが純粋なPythonコードを実行できないという制限がある。

  • つまり threading では、スレッドが複数あっても、CPUバウンド処理(計算など)は順番にしか実行されない

C言語などのネイティブコードやI/O操作中はGILを解放するため、threading でもI/Oバウンド処理には効果がある。


🧪例で理解する

🔁 スレッドで複数の処理を同時に走らせる

import threading
import time

def task(name):
    time.sleep(1)
    print(f"{name} 終了")

for i in range(3):
    threading.Thread(target=task, args=(f"タスク{i}",)).start()

→ 同時に3つの処理が並行で進む。


🌀 非同期で並行に処理する

import asyncio

async def task(name):
    await asyncio.sleep(1)
    print(f"{name} 終了")

async def main():
    await asyncio.gather(
        task("タスク0"),
        task("タスク1"),
        task("タスク2")
    )

asyncio.run(main())

→ 実行中に await があることで、他のタスクに切り替わりながら進む


🎯使い分けの判断ポイント

状況 おすすめ手段 理由
HTTPアクセスを多数同時にしたい asyncio 非同期にリクエストし、待ち時間を有効活用できる
GUIアプリで定期処理をバックグラウンド実行したい threading 非同期だとUIが止まる。別スレッドで動かすのが王道
CPUを食う重たい処理を複数並行で実行したい multiprocessing スレッドも非同期もGILの影響を受ける。別プロセスに分けるべき

📝まとめ

  • **スレッド(threading)**は「分身して動く」感覚。複雑な排他制御は必要だが、並列処理が可能。

  • **非同期(asyncio)**は「1人の職人が効率よく切り替える」スタイル。設計が綺麗で、I/Oに最適。

  • 両者は見た目が似ていても、中身の動作は全く違う。

  • GILの存在を意識して、「どんな処理を並行させたいのか?」で選ぶのがカギ。