Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
threading.Thread()
『threading』モジュールはスレッドを使って処理を並行実行するための標準ライブラリです。複数のスレッドが同時に動作し、I/O待ち(ファイル読み書き・ネットワーク通信など)の間に他の処理を進められます。PythonのGIL(グローバルインタープリタロック)により、CPUを多用する計算処理は真の並列実行にはなりません。CPU密集処理には代わりにmultiprocessingを使いましょう。
構文
import threading
# スレッドの生成と実行
t = threading.Thread(target=関数, args=(引数,))
t.start() # スレッド開始
t.join() # スレッドの終了を待つ
# 排他制御(Lock)
lock = threading.Lock()
with lock:
# クリティカルセクション
pass
クラス・メソッド一覧
| クラス・メソッド | 概要 |
|---|---|
| Thread(target, args, kwargs) | スレッドオブジェクトを生成する。 |
| t.start() | スレッドを開始する。 |
| t.join(timeout=None) | スレッドが終了するまでメインスレッドをブロックする。 |
| t.is_alive() | スレッドがまだ実行中かどうかを返す。 |
| t.daemon = True | デーモンスレッドに設定する。メインが終了すると自動で終了する。 |
| threading.Lock() | 排他制御のためのロックオブジェクトを生成する。 |
| lock.acquire() | ロックを取得する(withで代替推奨)。 |
| lock.release() | ロックを解放する(withで代替推奨)。 |
| threading.current_thread() | 現在実行中のスレッドオブジェクトを返す。 |
サンプルコード
import threading
import time
# 基本的なスレッドの作成と実行
def download(url, name):
print(f"[{name}] ダウンロード開始: {url}")
time.sleep(2) # ネットワーク処理のシミュレーション
print(f"[{name}] ダウンロード完了!")
# 逐次実行(約6秒)
# for url in urls: download(url)
# 並行実行(約2秒)
urls = ['https://example.com/file1', 'https://example.com/file2', 'https://example.com/file3']
threads = []
for i, url in enumerate(urls):
t = threading.Thread(target=download, args=(url, f"Thread-{i+1}"))
threads.append(t)
t.start()
for t in threads:
t.join() # すべてのスレッドの終了を待つ
print("すべてのダウンロードが完了しました")
# Lock: 共有リソースへの排他制御
counter = 0
lock = threading.Lock()
def increment(n):
global counter
for _ in range(n):
with lock: # ロックを取得してからカウンタを更新
counter += 1
threads = [threading.Thread(target=increment, args=(10000,)) for _ in range(5)]
for t in threads: t.start()
for t in threads: t.join()
print(f"カウンタ: {counter}") # 50000(Lockなしでは競合でズレる)
# クラスを継承したスレッド
class WorkerThread(threading.Thread):
def __init__(self, task_id):
super().__init__(daemon=True)
self.task_id = task_id
self.result = None
def run(self):
# start()を呼ぶとrun()が別スレッドで実行される
time.sleep(1)
self.result = self.task_id ** 2
workers = [WorkerThread(i) for i in range(5)]
for w in workers: w.start()
for w in workers: w.join()
print([w.result for w in workers]) # [0, 1, 4, 9, 16]
概要
スレッドが共有リソース(グローバル変数・ファイルなど)にアクセスするとき、排他制御(Lock)がないと競合状態(レースコンディション)が発生します。複数のスレッドが同時に読み書きを行うと、予測できない結果になる可能性があります。
PythonのGIL(グローバルインタープリタロック)はPythonオブジェクトへのアクセスをスレッドセーフにするための仕組みですが、同時に1つのスレッドしかPythonコードを実行できないことも意味します。そのため数値計算・画像処理などのCPU密集タスクには効果がなく、ファイルI/O・HTTPリクエストなどのI/O待ちタスクに有効です。CPU密集タスクの並列化にはmultiprocessingを使いましょう。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。