python终止线程
本文档来自: https://www. geeksforgeeks.org/pytho n-different-ways-to-kill-a-thread/
可以通过以下方式来终止线程:
- 通过抛出异常来终止线程
- 通过一个终止标志来终止线程
- 使用traces来终止线程
- 使用多线程模型来终止线程
- 通过将线程设置为deamon来终止线程
- 使用隐藏属性_stop()
- 通过抛出异常来终止线程
# 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()
运行以上程序,一旦raise_exception()被调用,run()函数将被终止。这是因为程序抛出异常,将不在try...finally...函数块中运行,run()函数即被终止。
2.通过一个终止标志来终止线程
# 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')
以上代码中,一旦全局变量stop_threads被置位,run()函数将终止,对应t1线程将因为t1.join()被终止。如果不使用全局变量,可以采用下面方式。
# 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()
上面代码中传递的函数对象始终返回局部变量stop_threads的值。 在函数run()中检查该值,并且一旦重置stop_threads,run()函数就会结束,并终止线程。
3.使用traces来终止线程
# 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.localtrace
else:
return None
def localtrace(self, frame, event, arg):
if self.killed:
if event == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
self.killed = True
def func():
while True:
print('thread running')
t1 = thread_with_trace(target = func)
t1.start()
time.sleep(2)
t1.kill()
t1.join()
if not t1.isAlive():
print('thread killed')
在此代码中,对start()进行了一些修改,以使用settrace()设置系统跟踪功能。 定义本地跟踪函数,以便每当设置了相应线程的kill标志(killed)时,在执行下一行代码时都会引发SystemExit异常,从而结束目标函数func的执行。 现在可以使用join()杀死线程。
4.使用多线程模型来终止线程
# Python program creating
# three threads
import threading
import time
# counts from 1 to 9
def func(number):
for i in range(1, 10):
time.sleep(0.01)
print('Thread ' + str(number) + ': prints ' + str(number*i))
# creates 3 threads
for i in range(0, 3):
thread = threading.Thread(target=func, args=(i,))
thread.start()
上面的代码的功能也可以通过使用多处理模块以类似的方式实现,只需要很少的更改即可实现。 请参阅下面给出的代码。
# Python program creating
# thread using multiprocessing
# module
import multiprocessing
import time
def func(number):
for i in range(1, 10):
time.sleep(0.01)
print('Processing ' + str(number) + ': prints ' + str(number*i))
for i in range(0, 3):
process = multiprocessing.Process(target=func, args=(i,))
process.start()
尽管两个模块的接口相似,但是两个模块的实现却大不相同。 所有线程共享全局变量,而线程则彼此完全分开。 因此,与杀死线程相比,杀死线程要安全得多。 为Process类提供了一个终止线程的方法Terminate()。 现在,回到最初的问题。 假设在上面的代码中,我们想在0.03秒过去之后终止所有线程。 使用以下代码中的多处理模块可实现此功能。
# Python program killing
# a thread using multiprocessing
# module
import multiprocessing
import time
def func(number):
for i in range(1, 10):
time.sleep(0.01)
print('Processing ' + str(number) + ': prints ' + str(number*i))
# list of all processes, so that they can be killed afterwards
all_processes = []
for i in range(0, 3):
process = multiprocessing.Process(target=func, args=(i,))
process.start()
all_processes.append(process)
# kill all processes after 0.03s
time.sleep(0.03)
for process in all_processes:
process.terminate()
虽然这两个模块具有不同的实现。 上面代码中的多处理模块提供的此功能类似于杀死线程。 因此,只要需要在Python中实现线程杀死,就可以将多处理模块用作简单的替代方法。
5.通过将线程设置为deamon来终止线程
import threading
import time
import sys
def func():
while True:
time.sleep(0.5)
print('Thread alive, and it won't die on program termination')
t1 = threading.Thread(target=func)
t1.start()
time.sleep(2)
sys.exit()
请注意,线程t1保持活动状态,并防止主程序通过sys.exit()退出。 在Python中,任何活动的非守护线程都会阻止主程序退出。 而守护程序线程本身在主程序退出时就被杀死。 换句话说,一旦主程序退出,所有守护程序线程就会被杀死。 要将线程声明为守护程序,我们将关键字参数daemon设置为True。 对于给定代码中的Example,它演示了守护程序线程的属性。
# Python program killing
# thread using daemon
import threading
import time
import sys
def func():
while True:
time.sleep(0.5)
print('Thread alive, but it will die on program termination')
t1 = threading.Thread(target=func)
t1.daemon = True
t1.start()
time.sleep(2)
sys.exit()
注意,一旦主程序退出,线程t1将被杀死。 在可以使用程序终止来触发线程终止的情况下,该方法被证明非常有用。 请注意,在Python中,一旦所有非守护程序线程都死了,则主程序将终止,而与存活的守护程序线程数无关。 因此,这些守护线程所拥有的资源(例如打开的文件,数据库事务等)可能无法正确释放。 python程序中的初始控制线程不是守护程序线程。 除非可以肯定,否则不建议强行杀死线程,因为这样做不会导致任何泄漏或死锁。
6.使用隐藏属性_stop()
为了杀死线程,我们使用了隐藏函数_stop(),该函数没有文档说明,但可能会在下一版本的python中消失。
# Python program killing
# a thread using ._stop()
# function
import time
import threading
class MyThread(threading.Thread):
# Thread class with a _stop() method.
# The thread itself has to check
# regularly for the stopped() condition.
def __init__(self, *args, **kwargs):
super(MyThread, self).__init__(*args, **kwargs)
self._stop = threading.Event()
# function using _stop function
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
def run(self):
while True:
if self.stopped():
return
print("Hello, world!")
time.sleep(1)