Python のスレッドとは

スレッドとは、プログラム内で並行して実行される処理の単位です。1つのプログラム(プロセス)の中で複数のスレッドを動かすことで、複数の処理を同時に進められます。

スレッドの基本概念

通常、プログラムは上から下へ順番に実行されます。しかしスレッドを使うと、複数の処理を「同時に」実行できます。

import threading
import time

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

# 2つのスレッドを作成
t1 = threading.Thread(target=task, args=("タスクA",))
t2 = threading.Thread(target=task, args=("タスクB",))

t1.start()
t2.start()

t1.join()
t2.join()
print("すべて完了")

この例では、タスクAとタスクBがほぼ同時に実行されるため、合計4秒ではなく約2秒で完了します。

プロセスとスレッドの違い

プロセス

独立したメモリ空間を持つ。プロセス間のデータ共有は複雑。作成コストが高い。

スレッド

同じメモリ空間を共有する。データ共有が容易。作成コストが低い。

スレッドは同じプロセス内でメモリを共有するため、データのやり取りが簡単ですが、同時アクセスによる競合に注意が必要です。

スレッドが有効な場面

スレッドは特に I/O 待ちが多い処理で効果を発揮します。

I/O バウンドな処理

ファイル読み書き、ネットワーク通信、データベースアクセスなど。待ち時間中に他の処理を進められる。

ユーザーインターフェース

メインスレッドで UI を描画しつつ、バックグラウンドで重い処理を実行。

import threading
import urllib.request

def download(url):
    print(f"ダウンロード開始: {url}")
    response = urllib.request.urlopen(url)
    data = response.read()
    print(f"ダウンロード完了: {url} ({len(data)} bytes)")

urls = [
    "https://example.com",
    "https://example.org",
    "https://example.net",
]

threads = [threading.Thread(target=download, args=(url,)) for url in urls]

for t in threads:
    t.start()

for t in threads:
    t.join()

3つの URL を並行してダウンロードするため、順番に処理するより大幅に高速化できます。

メインスレッド

Python プログラムは起動時に「メインスレッド」で実行を開始します。新しいスレッドを作成しなければ、すべての処理はメインスレッドで順番に実行されます。

import threading

print(f"現在のスレッド: {threading.current_thread().name}")
# 出力: 現在のスレッド: MainThread

注意点

スレッドは便利ですが、いくつかの注意点があります。

データ競合

複数のスレッドが同じデータを同時に変更すると、予期しない結果になる可能性がある。

GIL の制約

Python の GIL(Global Interpreter Lock)により、CPU バウンドな処理では並列化の効果が限定的。

スレッドを使う際は、これらの特性を理解した上で適切に設計することが重要です。