
کلاس Timer
کلاس Timer یکی از زیرکلاسهای Thread در ماژول threading است و به شما اجازه میدهد یک تابع را نه بلافاصله، بلکه پس از گذشت یک بازهی زمانی مشخص اجرا کنید. به عبارت ساده، Timer مثل یک زنگ هشدار عمل میکند: زمان را تنظیم میکنید، برنامه به کار خود ادامه میدهد، و وقتی زمان تعیینشده فرا رسید، تابع موردنظر در یک ترد جداگانه اجرا میشود.
مهمترین ویژگی Timer این است که چون یک ترد مستقل است، منتظر ماندنِ آن، جریان اصلی برنامه را متوقف نمیکند؛ برنامهی شما بدون وقفه ادامه پیدا میکند و تابع در زمان مقرر «در پسزمینه» صدا زده میشود.
ساختار و پارامترها
امضای این کلاس به شکل Timer(interval, function, args=None, kwargs=None) است:
| پارامتر | توضیح |
|---|---|
interval | مدت تأخیر برحسب ثانیه (میتواند اعشاری هم باشد، مثل 0.5). |
function | تابعی که بعد از پایان تأخیر اجرا میشود. |
args | آرگومانهای موضعی (بهصورت tuple یا list) که به تابع پاس داده میشوند. |
kwargs | آرگومانهای کلیدواژهای (بهصورت dict) که به تابع پاس داده میشوند. |
و مهمترین متدهای آن: start() برای شروع شمارش تأخیر، و cancel() برای لغو اجرا (تا زمانی که هنوز تابع اجرا نشده باشد).
اجرای تابع با تأخیر
from threading import Timer
def say_hi(name):
print('hi', name)
# run say_hi after 3 seconds
Timer(3, say_hi, args=('mmreza', )).start()در تکهکد بالا، تابع say_hi پس از ۳ ثانیه اجرا میشود. توجه کنید که برنامه بلافاصله از خط Timer(...).start() عبور میکند و منتظر نمیماند؛ صرفاً یک ترد زمانبندیشده ساخته میشود که سه ثانیه بعد تابع را صدا میزند.
لغو اجرا با cancel()
برای لغو اجرا میتوانید قبل از فرا رسیدن زمان اجرا از متد cancel استفاده کنید. اگر تابع هنوز اجرا نشده باشد، cancel جلوی اجرای آن را میگیرد؛ اما اگر زمان تأخیر تمام شده و تابع شروع به اجرا کرده باشد، دیگر cancel اثری ندارد. به مثال زیر توجه کنید:
from threading import Timer
def say_hi(name):
print('hi', name)
say_hi_after_3_seconds = Timer(3, say_hi, args=('mmreza', ))
say_hi_after_3_seconds.start()
say_hi_after_3_seconds.cancel() # cancels before the 3s elapses, so say_hi never runsدر این مثال چون cancel بلافاصله بعد از start و خیلی زودتر از پایان سه ثانیه فراخوانی میشود، تابع say_hi هرگز اجرا نمیشود و هیچ خروجیای چاپ نمیگردد. اگر بین start و cancel بیش از سه ثانیه فاصله میافتاد، تابع اجرا شده بود و cancel دیگر کاری نمیکرد.
اجرای دورهای (تکرارشونده)
خودِ Timer ذاتاً «یکبارمصرف» است و تابع را فقط یک بار اجرا میکند. اما با ساختن یک Timer جدید در انتهای همان تابع، میتوان یک رفتار تکرارشونده ساخت. در مثال زیر تابع tick هر یک ثانیه یک بار و در مجموع سه بار اجرا میشود:
from threading import Timer
count = 0
def tick():
global count, timer
count += 1
print('tick', count)
if count < 3: # schedule the next run
timer = Timer(1, tick)
timer.start()
timer = Timer(1, tick)
timer.start()هر بار که tick اجرا میشود، اگر هنوز به سقف تعیینشده نرسیده باشیم یک Timer تازه برای اجرای بعدی میسازد. برای متوقفکردن این چرخه کافی است شرط ادامه را برقرار نکنید یا روی آخرین تایمر cancel را صدا بزنید.
موارد استفاده
برخی از کاربردهای رایج Timer عبارتاند از:
- اجرای وظایف بهتأخیرافتاده: اجرای یک عملیات بعد از مدتزمانی مشخص، مثل ارسال یک یادآوری یا انجام یک عملیات پاکسازی.
- زمانبندی وظایف دورهای: هرچند
Timerبرای کارهای تکباره طراحی شده، با اجرای دوبارهی تایمر در انتهای تابع میتوان یک عملکرد تکرارشونده ساخت. - ارسال اعلانها و یادآوریها: اطلاعرسانی به کاربر برای انجام یک کار خاص بعد از گذشت مدتزمانی معین.
- عملیات با تأخیر در شبکه: در بسیاری از پروتکلها به سازوکارهای timeout و retry نیاز است که با تأخیر زمانی کار میکنند.
- مدیریت زمانبندی در بازیها: اجرای رویدادها، تولید دشمن جدید، یا تغییر امتیاز بازیکن پس از مدتزمانی مشخص.
- کنترل رباتها و سیستمهای اتوماسیون: زمانبندی دقیق اجرای عملیات و توالیهای کاری در سیستمهای صنعتی و رباتیک.
مثالهای کاربردی
ارسال یادآوری به کاربر
import threading
def send_reminder():
print("It's time to take a break!")
# send a reminder after 3600 seconds (1 hour)
reminder_timer = threading.Timer(3600, send_reminder)
reminder_timer.start()زمانبندی پاکسازی حافظهی موقت
import threading
def cleanup_cache():
print("Cleaning up cache...")
# clean the cache after 600 seconds (10 minutes)
cache_cleanup_timer = threading.Timer(600, cleanup_cache)
cache_cleanup_timer.start()اطلاعرسانی دربارهی وضعیت یک ترد
در این مثال یک وظیفهی زمانبر داریم و میخواهیم اگر بعد از ۳ ثانیه هنوز تمام نشده بود، به کاربر پیام بدهیم که «هنوز در حال اجراست». اینجا Timer نقش یک ناظر را بازی میکند که وضعیت ترد اصلی را با is_alive() بررسی میکند:
import time
from threading import Thread, Timer
def task(name):
print(f'task {name} started')
time.sleep(5)
print(f'task {name} finished')
def check_thread_status(thread):
if thread.is_alive():
print(f"{thread.name} is still running! please wait ...")
t1 = Thread(target=task, args=(1, ))
timer = Timer(3, check_thread_status, args=(t1, ))
t1.start()
timer.start()چون task پنج ثانیه طول میکشد، سه ثانیه بعد از شروع، تایمر تابع check_thread_status را صدا میزند؛ در آن لحظه ترد هنوز زنده است و پیام هشدار چاپ میشود. در نهایت پس از پایان پنج ثانیه، پیام «finished» نمایش داده میشود.
در هر یک از این مثالها، Timer به شما امکان میدهد عملیاتی را بعد از مدتزمانی مشخص اجرا کنید، بدون اینکه نیاز به حلقههای پیچیده یا مدیریت دستی زمان داشته باشید.
مقایسه Timer با sleep
بهدلیل شباهت ظاهری Timer و sleep، گاهی ممکن است در انتخاب میان آنها دچار سردرگمی شوید. تفاوت اصلی این است که Timer یک تابع را در یک ترد جداگانه و با تأخیر اجرا میکند و جریان برنامه را متوقف نمیکند؛ اما sleep صرفاً همان تردی را که در آن فراخوانی شده، برای مدتی متوقف (بلاک) میکند.
| ویژگی | Timer | sleep |
|---|---|---|
| کارکرد | اجرای یک تابع با تأخیر | ایجاد وقفه در اجرای ترد فعلی |
| مسدودکردن جریان برنامه | خیر (در ترد جدا اجرا میشود) | بله (ترد فعلی را متوقف میکند) |
| قابل لغو بودن | بله، با cancel() پیش از اجرا | خیر، بهراحتی قابل لغو نیست |
| مناسب برای | زمانبندی یک کار برای آینده | مکث ساده در همین جریان اجرا |
بهطور خلاصه، اجرای تردی که با Timer بهتأخیر افتاده را میتوان پیش از اجرا شدنش لغو کرد، اما وقفهای که با sleep ایجاد شده بهسادگی قابل لغو نیست.
خلاصه
Timerزیرکلاسی ازThreadاست که یک تابع را پس از تأخیری مشخص، در یک ترد جداگانه اجرا میکند.- با
start()شمارش آغاز میشود و باcancel()میتوان اجرا را — تنها پیش از فرا رسیدن زمان — لغو کرد. - برای اجرای دورهای، در انتهای تابع یک
Timerجدید بسازید. - برخلاف
sleepکه ترد فعلی را بلاک میکند،Timerجریان اصلی برنامه را متوقف نمیکند و قابل لغو است.