python终止线程

可以通过以下方式来终止线程:

  • 通过抛出异常来终止进程
  • 通过一个终止标志来终止进程
  • 使用traces来终止进程
  • 使用多线程模型来终止进程
  • 通过将进程设置为deamon来终止进程
  • 使用隐藏属性_stop()
  1. 通过抛出异常来终止进程
# 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) 

t1 = MyThread() 

t1.start() 
time.sleep(5) 
t1.stop() 
t1.join() 

注意:上面的方法在某些情况下可能不起作用,因为python没有提供任何直接的方法来杀死线程。

参考文档:

https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/

Leave a Reply

Your email address will not be published. Required fields are marked *