Python threading.Timerとは?指定秒後に処理を実行する方法
threading.Timerは、指定した秒数が経ってから関数を実行するクラスです。
time.sleep()と違い、待っている間もプログラムは先に進みます。
Timerの基本
import threading
import time
def hello():
print("3秒後に実行")
t = threading.Timer(3, hello)
t.start()
print("Timer開始(まだ実行されない)")
time.sleep (4)
実行結果:
Timer開始(まだ実行されない)
3秒後に実行
第1引数が秒数、第2引数が実行する関数です。
start()を呼ばないと動きません。作っただけでは何も起きない点に注意してください。
引数を渡す
def hello(name, greeting="こんにちは"):
print(f"{greeting}、{name}さん")
threading.Timer(0.1, hello,
args=("田中",),
kwargs={"greeting": "やあ"}).start()
実行結果:
やあ、田中さん
Threadと同じくargsはタプルです。引数が1個なら("田中",)とカンマを付けてください。
cancel()で取り消す
t = threading.Timer(5, hello)
t.start()
t.cancel()
print("cancel直後 is_alive:", t.is_alive())
time.sleep (0.1)
print("少し待つと:", t.is_alive())
実行結果:
cancel直後 is_alive: True
少し待つと: False
cancel()は「取り消しを依頼する」だけで、スレッドが終わるまでにわずかな時間差があります。
確実に終わったことを確認したいなら、cancel()のあとにjoin()を呼んでください。
すでに実行されたあとのcancel()は何も起きません——エラーにもなりません。
Timerはスレッドである
t = threading.Timer(1, hello)
print(isinstance(t, threading.Thread))
実行結果:
True
TimerはThreadのサブクラスです。つまり1つのTimerにつき1つのスレッドが作られます。
ここから2つの注意点が出てきます。
- 大量に作るとスレッドが増えすぎる——数千個のタイマーには向かない
- デフォルトでは非デーモンなので、実行を待ってからプログラムが終わる
t = threading.Timer(10, hello)
t.daemon = True # start前に設定
t.start()
daemon = Trueにすれば、メイン終了時に道連れで終わります。「Pythonのデーモンスレッドとは?daemon=Trueの意味と注意点」を参照してください。
繰り返し実行する
Timerは1回しか実行しません。繰り返したいときは、自分の中で作り直します。
import threading
count = 0
def tick():
global count
count += 1
print("tick", count)
if count < 3:
threading.Timer(0.1, tick).start()
tick()
実行結果:
tick 1
tick 2
tick 3
終了条件を必ず入れてください。条件を書き忘れると、止める手段がないまま永久に動き続けます。
停止できるようにするなら、Eventと組み合わせるか、作ったTimerを変数に保持してcancel()できるようにします。
精度は保証されない
import time
s = time.perf_counter()
ev = threading.Event()
threading.Timer(0.5, ev.set).start()
ev.wait()
print(f"指定0.5秒 → 実測{time.perf_counter() - s:.3f}秒")
実行結果:
指定0.5秒 → 実測0.505秒
「指定秒数以上待つ」ことは保証されますが、ぴったりではありません。
スレッドの起動や他の処理の影響で、必ず少し遅れます。ミリ秒単位の正確さが要る用途には使えません。
sleepとの使い分け
time.sleep() |
Timer |
|
|---|---|---|
| 呼び出し側 | 止まる | 止まらない |
| 取り消し | できない | cancel() |
| スレッド | 増えない | 1つ増える |
順番に待てばよいだけならtime.sleep()で十分です。
待ちながら他の処理を続けたい、あとで取り消したい——そのときがTimerの出番です。
Timerのまとめ
Timer(秒数, 関数)を作ってstart()で開始argsはタプル(引数1個ならカンマ必須)cancel()で取り消せる——終了確認はjoin()- 1つにつきスレッド1本——大量生成は避ける
- 実行は1回だけ——繰り返すなら作り直す
- 精度は保証されない(指定秒数以上)


