ویژگی daemon
برای اجرای یک ترد در پسزمینه میتوان آن را به صورت daemon تعریف کرد. ترد ها به صورت پیشفرض daemon نیستند. استفاده از ترد های daemon برای توسعه سناریو های فرعی کمک کننده است.
سناریوی فرعی، سناریویی است که حذف کردن آن خللی در اجرا ایجاد نکند و برنامه بتواند متناسب با هدفی که برای آن توسعه یافته است همچنان خروجی بدهد. موارد زیر نمونه هایی از سناریو های فرعی هستند.
- مانیتورینگ منابع هنگام اجرا
- ارسال گزارش هنگام اجرا
- ارسال اعلانات یا هشدار هایی هنگام اجرا
- پاکسازی حافظه یا کش هنگام اجرا
- ذخیره سازی خودکار یا پشتیبان گیری خودکار هنگام اجرا
مثال – اطلاع رسانی به کاربر
یک برنامه داریم که اجرای آن مدت زمان قابل توجهی طول خواهد کشید. در این هنگام ممکن است کاربر تصور کند که اجرای برنامه با مشکل مواجه شده و کل برنامه را متوقف کند. برای اینکه به کاربر اطلاع دهیم که همه چیز در حالت طبیعی در حال اجراست باید کاربر را از پیشرفت برنامه مطلع سازیم.
بدین منظور check_thread_status را توسعه داده ایم که یک ترد میگیرد و اگر اجرایش بیش از سه ثانیه طول بکشد، با نمایش یک پیام از کاربر میخواهد که بیشتر صبر کند.
import time
from threading import Thread
def task(name):
print(f'task {name} started')
time.sleep(1)
print(f'task {name} finished')
def check_thread_status(thread):
time.sleep(3)
if thread.is_alive():
print(f"{thread.name} is still running! please wait ...")
t1 = Thread(target=task, args=(1, ))
t2 = Thread(target=check_thread_status, args=(t1, ))
t1.start()
t2.start()توضیح کد بالا:
- خط ۴ تا ۷: تابع
taskرا تعریف کردهایم که اجرایش یک ثانیه طول میکشد. - خط ۹ تا ۱۲: تابع
check_thread_statusرا داریم که یک ترد میگیرد و پس از سه ثانیه اگر ترد هنوز در حال اجرا باشد یک پیام به کاربر نمایش میدهد و او را از وضعیت اجرای ترد مطلع میسازد. - خط ۱۴: یک thread به نام t1 میسازیم که تابع
taskرا اجرا میکند. - خط ۱۵: یک thread به نام t2 میسازیم که تابع
check_thread_statusرا اجرا میکند.
مشکل کد بالا این است که تسک اصلی در یک ثانیه به صورت کامل اجرا میشود ولی چون check_thread_status سه ثانیه صبر میکند، اجرای کل برنامه سه ثانیه زمان میبرد.
اکنون با اصلاح کد بالا به شکل زیر، check_thread_status را وادار میکنیم در پسزمینه اجرا شود.
import time
from threading import Thread
def task(name):
print(f'task {name} started')
time.sleep(1)
print(f'task {name} finished')
def check_thread_status(thread):
time.sleep(3)
if thread.is_alive():
print(f"{thread.name} is still running! please wait ...")
t1 = Thread(target=task, args=(1, ))
t2 = Thread(target=check_thread_status, args=(t1, ), daemon=True)
t1.start()
t2.start()انواع حالات تعریف daemon
دو روش برای تعریف یک ترد به صورت daemon وجود دارد.
۱. روش اول – هنگام تعریف ترد
t2 = Thread(target=check_thread_status, args=(t1, ), daemon=True)۲. روش دوم – پس از تعریف ترد
t2 = Thread(target=check_thread_status, args=(t1, ))
t2.daemon = Trueمتد های کاربردی daemon
isDaemon
مقدار ویژگی daemon یک ترد را برمیگرداند.
setDaemon
یک ورودی از نوع boolean میگیرد و براساس آن مقدار daemon یک ترد را تنظیم میکند.
نکته مهم در مورد متدها
این متدها منسوخ شدهاند و پیشنهاد میشود به صورت مستقیم با ویژگی daemon کار کنید. به مثال زیر توجه کنید.
import time
from threading import Thread
def say_hi(name):
time.sleep(1)
print('hi', name)
t1 = Thread(target=say_hi, args=('Ali', ))
t2 = Thread(target=say_hi, args=('Firooze', ))
t3 = Thread(target=say_hi, args=('Hamid', ), daemon=True)
t4 = Thread(target=say_hi, args=('Saeed', ))
t4.daemon = True # روش خوب
t4.setDaemon(True) # روش منسوخ شده
t1.start()
t2.start()
t3.start()
t4.start()
print('t1', t1.daemon) # روش خوب
print('t1', t1.isDaemon()) # روش منسوخ شده
print('t2', t2.daemon) # روش خوب
print('t2', t2.isDaemon()) # روش منسوخ شده
print('t3', t3.daemon) # روش خوب
print('t3', t3.isDaemon()) # روش منسوخ شده
print('t4', t4.daemon) # روش خوب
print('t4', t4.isDaemon()) # روش منسوخ شدهنکته مهم در مورد تنظیم daemon
اگر بخواهید مقدار daemon را پس از فراخوانی متد start تغییر دهید با خطای RuntimeError مواجه خواهید شد.
به مثال زیر توجه کنید. این کد خطای RuntimeError دارد.
import time
from threading import Thread
def say_hi(name):
time.sleep(1)
print('hi', name)
t1 = Thread(target=say_hi, args=('mmreza', ))
t1.start()
t1.daemon = True # نباید بعد start تنظیم شودخلاصه
| ویژگی | daemon False | daemon True |
| پیشفرض | ✅ | ❌ |
| اجرا در پسزمینه | ❌ | ✅ |
| پایان زندگی | اجازه میدهد تا پایان زندگی برنامه اصلی (main thread) باقی بماند. | اگر تمام ترد های غیر دیمون خاتمه یابند، به طور خودکار بسته میشود. |