Pythonでプログラムを作成している際、「5秒おきにセンサーの値を読み取りたい」「メインの処理を止めずに、裏側で1分ごとにログを出力したい」といった、定期実行(周期処理)が必要になる場面は多いですよね。
特に通信アプリや組み込み系の制御ソフトを制作していると、周期的なイベント制御は必須のテクニックです。
Pythonでこれを実現する方法はいくつかありますが、標準ライブラリの threading.Timer を使うのが最も手軽で強力です。本記事では、初心者の方でもすぐに実装できる基本形から、実戦で役立つ「クラス化による管理術」まで、詳しく解説します。
1. Pythonで定期実行を実現する主な手法
まず、定期実行にはいくつかの方法があります。自分の目的に合っているか確認しましょう。
| 手法 | 難易度 | メイン処理 | 特徴 |
| while + sleep | 低 | 停止する | 最も簡単だが、待機中は他の処理ができない。 |
| threading.Timer | 中 | 動く | 標準機能のみで完結。非同期で裏側で動かせる。 |
| scheduleライブラリ | 低 | 動く | 直感的に書けるが、外部ライブラリのインストールが必要。 |
「メインのループは回し続けたいけれど、裏で定期的なタスクも走らせたい」という場合は、今回紹介する threading.Timer が最適です。
2. threading.Timerとは?
threading.Timer は、Pythonの標準ライブラリ threading モジュールに含まれるクラスです。
指定した時間が経過した後に、特定の関数(コールバック関数)を別のスレッドで実行してくれます。「スレッド」を使用するため、タイマーが待機している間も、メインのプログラムは止まらずに動作し続けるのが最大のメリットです。
3. 【基本】threading.Timerで1回だけ実行する
まずは最もシンプルな「◯秒後に1回だけ実行する」コードを見てみましょう。
import threading
def hello():
print("3秒経過しました!")
# 1. タイマーのインスタンス作成 (秒数, 実行する関数)
t = threading.Timer(3.0, hello)
# 2. タイマー開始
t.start()
print("タイマー開始後、すぐにこの行が実行されます(非同期)")4. 【実践】Timerを「周期的に」動かす再帰の実装方法
threading.Timer はデフォルトでは「1回きり」の動作です。これを周期的に動かすには、実行される関数の中でもう一度タイマーをセットする(再帰呼び出し)というテクニックを使います。
サンプルコード
import threading
import time
def periodic_task():
print(f"実行時刻: {time.ctime()}")
# 処理が終わったら、再度タイマーをセットして起動(1秒周期)
global timer
timer = threading.Timer(1.0, periodic_task)
timer.start()
# 初回の起動
periodic_task()
# 5秒間メイン処理を走らせる
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("停止中...")
timer.cancel() # タイマーを止める5. 【応用】クラス化して可読性と再利用性を高める
実戦のアプリ開発では、グローバル変数を使うよりもクラスとして定義したほうが、タイマーの開始・停止が管理しやすくなります。
コピペで使える「周期タイマークラス」
import threading
import time
class RepeatingTimer(threading.Timer):
def run(self):
# cancel()が呼ばれるまで繰り返す
while not self.finished.wait(self.interval):
self.function(*self.args, **self.kwargs)
# 使い方
def my_task(name):
print(f"Hello, {name}! Time: {time.ctime()}")
# 2秒おきに my_task("Python") を実行
tm = RepeatingTimer(2.0, my_task, args=("Python",))
tm.start()
time.sleep(7) # 7秒間動かす
tm.cancel() # タイマー停止
print("タイマーを停止しました。")6. 知っておきたい!Timerを使う時の注意点
非常に便利な threading.Timer ですが、以下の点には注意が必要です。
- 実行時間のズレ(ドリフト):Pythonの
Timerは厳密なリアルタイム性を保証するものではありません。OSの負荷や処理時間の影響で、数ミリ秒〜数十ミリ秒程度の遅延が発生することがあります。 - スレッドセーフ:メイン処理とタイマー処理で同じ変数を書き換える場合は、データの整合性に注意が必要です。
- デーモンスレッド:メインのプログラムが終了してもタイマーが残り続けることがあります。必要に応じて
cancel()を確実に呼ぶようにしましょう。
7. まとめ
Pythonの threading.Timer を使えば、メイン処理の邪魔をせずにスマートな周期処理を実装できます。
- 1回だけ実行: シンプルな
Timer(秒, 関数) - 周期実行: 関数内での再起動、またはクラス化を推奨
- 非同期: メインループを止めずに済む
組み込み機器のポーリング処理や、定期的なステータスチェックなど、ぜひ活用してみてください!


コメント