آیا راهی برای متوقف کردن Thread در پایتون وجود دارد؟
در زبانهای برنامهنویسی، به ویژه Python، متوقف کردن ناگهانی یک Thread یک الگوی بد و خطرناک به حساب میآید. به دلیل اینکه انجام این کار میتواند به عواقب ناخواستهای چون نشت حافظه یا قفل شدگی منجر شود، در اکثر موارد توصیه میشود که از روشهای ایمنتری استفاده کنید.
بهتر است در طراحی چند نخی، یک flag برای خروج (exit_request) تعریف کنید که Thread بطور منظم آن را چک کند تا بفهمد آیا باید متوقف شود یا خیر. نمونهای از این کد به شکل زیر است:
import threading
class StoppableThread(threading.Thread):
def __init__(self, *args, **kwargs):
super(StoppableThread, self).__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
در این کد، میتوانید با فراخوانی متد stop()
بر روی Thread، آن را بدون مشکل متوقف کنید و با استفاده از join()
منتظر پایان Thread بمانید.
در موارد خاص، ممکن است نیاز باشد که Thread را بهطور مستقیم متوقف کنید، مانند زمانی که یک کتابخانه خارجی نیاز به قطع شدن دارد. این کار از طریق ایجاد یک exception در Thread انجام میشود. هرچند این راهکار نیز به خودی خود ایمن نیست و اگر Thread در حال اجرای یک کد بلوکدار باشد، استثنا نادیده گرفته خواهد شد.
مثالی از این روش به صورت زیر است:
import ctypes
import threading
def _async_raise(tid, exctype):
if not inspect.isclass(exctype):
raise TypeError("Only types can be raised (not instances)")
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), None)
raise SystemError("PyThreadState_SetAsyncExc failed")
لذا اگرچه شما میتوانید از این تکنیکها برای توقف یک Thread استفاده کنید، اما بهتر است از آنها با احتیاط و به عنوان آخرین راه حل استفاده کنید.
همچنین میتوانید به جای استفاده از Threads از multiprocessing.Process
استفاده کنید که به شما اجازه میدهد فرایندهای کاملاً جدیدی ایجاد کنید. این روش مزیتی دارد که میتوانید با استفاده از terminate()
بهسرعت یک فرایند را متوقف کنید بدون اینکه نگران وضعیت Threads باشید.
به عنوان مثال:
import multiprocessing
proc = multiprocessing.Process(target=your_proc_function, args=())
proc.start()
proc.terminate() # sends a SIGTERM
در نهایت، هیچ API رسمی برای کشتن Thread وجود ندارد و اقدام برای این کار از طریق APIهای پلتفرم مانند pthread_kill
یا TerminateThread
امکانپذیر است؛ اما این روشها به دلیل خطرات ذاتی خود عموماً توصیه نمیشوند.