Python | 终止线程的几种不同方法

通常情况下,强制终止线程被认为是一种糟糕的编程习惯。突然杀死一个线程可能会导致某些必须正确关闭的关键资源处于打开状态。但是,我们可能希望在经过特定时间段或产生某些中断时终止线程。在 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
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/43508.html
点赞
0.00 平均评分 (0% 分数) - 0