通常情况下,强制终止线程被认为是一种糟糕的编程习惯。突然杀死一个线程可能会导致某些必须正确关闭的关键资源处于打开状态。但是,我们可能希望在经过特定时间段或产生某些中断时终止线程。在 Python 中,我们有多种方法可以用来终止线程。
- 在 Python 线程中抛出异常
- 设置/重置停止标志
- 使用跟踪来终止线程
- 使用 multiprocessing 模块终止线程
- 通过将线程设置为守护进程来终止
- 使用隐藏函数 _stop()
#### 在 Python 线程中抛出异常
这种方法使用 PyThreadState_SetAsyncExc() 函数在 a 线程中引发异常。例如,
# Python program raising
# exceptions in a python
# thread
import threading
import ctypes
import time
class thread_with_exception(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
# target function of the thread class
try:
while True:
print(‘running ‘ + self.name)
finally:
print(‘ended‘)
def get_id(self):
# returns id of the respective thread
if hasattr(self, ‘_thread_id‘):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def raise_exception(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,
ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print(‘Exception raise failure‘)
t1 = thread_with_exception(‘Thread 1‘)
t1.start()
time.sleep(2)
t1.raise_exception()
t1.join()
当我们在机器上运行上述代码时,我们会注意到,一旦函数 INLINECODE64e9406c 被调用,目标函数 INLINECODE83c853e6 就会结束。这是因为一旦引发异常,程序控制就会跳出 try 块,INLINECODE20000774 函数随之终止。之后可以调用 INLINECODEc1f297d0 函数来终止线程。如果没有 INLINECODEaa736d55 函数,目标函数 INLINECODEfe641219 将无限期运行,并且永远不会调用 join() 函数来终止线程。
#### 设置/重置停止标志
为了终止线程,我们可以声明一个停止标志,线程会定期检查这个标志。例如:
# Python program showing
# how to kill threads
# using set/reset stop
# flag
import threading
import time
def run():
while True:
print(‘thread running‘)
global stop_threads
if stop_threads:
break
stop_threads = False
t1 = threading.Thread(target = run)
t1.start()
time.sleep(1)
stop_threads = True
t1.join()
print(‘thread killed‘)
在上述代码中,一旦设置了全局变量 INLINECODE51fa9ed4,目标函数 INLINECODEf8018c8f 就会结束,然后可以使用 INLINECODEf4801c64 终止线程 INLINECODEc7464b0a。但由于某些原因,大家可能会避免使用全局变量。对于这些情况,我们可以传入函数对象以提供类似的功能,如下所示。
# Python program killing
# threads using stop
# flag
import threading
import time
def run(stop):
while True:
print(‘thread running‘)
if stop():
break
def main():
stop_threads = False
t1 = threading.Thread(target = run, args =(lambda : stop_threads, ))
t1.start()
time.sleep(1)
stop_threads = True
t1.join()
print(‘thread killed‘)
main()
上述代码中传入的函数对象总是返回局部变量 INLINECODE2ba5deac 的值。这个值在 INLINECODE58395abd 函数中被检查,一旦 INLINECODEdd0692df 被重置,INLINECODE8a2d735c 函数就会结束,线程也就随之终止。
#### 使用跟踪来终止线程
这种方法通过在每个线程中安装跟踪来工作。每个跟踪在检测到某些刺激或标志时会自行终止,从而立即杀死关联的线程。例如:
# Python program using
# traces to kill threads
import sys
import trace
import threading
import time
class thread_with_trace(threading.Thread):
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
self.__run_backup = self.run
self.run = self.__run
threading.Thread.start(self)
def __run(self):
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, event, arg):
if event == ‘call‘:
return self.localtra