Python 3 -如何立即终止一个线程?

s5a0g9ez  于 2022-11-26  发布在  Python
关注(0)|答案(2)|浏览(388)

在我的代码(一个使用Tkinter的复杂GUI应用程序)中,我在一个自定义对象(一个进度条)中定义了一个线程,它运行一个带有while cicle的函数,如下所示:

def Start(self):
    while self.is_active==True:
        do it..
        time.sleep(1)
        do it..
        time.sleep(1)
    
def Stop(self):
    self.is_active=False

只有当另一个线程中的另一段代码使用方法self.Stop()更改属性self.is_active时,它才会终止。我在另一个自定义对象(计数器)中也遇到了同样的情况,当另一个线程(主线程)工作时,这两个对象必须一起工作。
代码运行正常,但我意识到与进度条和计数器相关的两个线程并没有像我希望的那样立即终止,因为在终止之前,它们需要等待其函数的结束,而这些线程由于**时间的原因速度很慢。sleep(1)**说明书.从用户Angular 出发,这意味着看到主线程的结束与进度条和cunter终止LATE,我不喜欢它。
老实说,我不知道如何解决这个问题。有没有办法强迫线程立即终止,而不等待函数结束?

55ooxyrt

55ooxyrt1#

首先,要明确的是,hard-killing a thread is a terrible idea in any language, and Python doesn't support it;如果没有其他问题的话,线程持有一个从未解锁的锁,导致任何试图获取它的线程死锁的风险就是一个致命的缺陷。
如果你根本不关心线程,你可以用daemon=True参数创建它,如果进程中的所有非守护线程都退出了,它就会死亡。(例如,它可能具有管理进程外部资源的清除的with语句等,其在进程终止时不会被清除),那不是真实的解决办法
也就是说,通过从使用普通的booltime.sleep转换到使用Event并在其上使用.wait方法,可以避免等待一秒钟或更长时间。(因为Event.wait仅在其为false/unset时阻塞,所以您需要基于应该停止的时间而不是当前活动的时间来设置标志):

class Spam:
    def __init__(self):
        self.should_stop = threading.Event()  # Create an unset event on init
    
    def Start(self):
        while not self.should_stop.is_set():
            # do it..

            if self.should_stop.wait(1):
                break

            # do it..

            if self.should_stop.wait(1):
                break

    def Stop(self):
        self.should_stop.set()

关于现代Python(3.1及更高版本)如果设置了事件,则wait方法返回True(在开始等待时或因为它在等待时被设置),否则为False,所以每当wait返回True时,这意味着您被告知停止,您可以立即break退出循环。您也几乎立即得到通知,而不是在可以检查标志之前等待一秒钟。
这不会导致真实的的“do it..”代码立即退出,但从您所说的内容来看,这部分代码似乎并不长,因此等待它完成并不是一件很麻烦的事情。
如果您确实想保留is_active属性以测试它是否仍处于活动状态,则可以将其定义为与Event含义相反的属性,例如:

@property
 def is_active(self):
     return not self.should_stop.is_set()
1bqhqjot

1bqhqjot2#

最安全的方法是返回。

def Start(self):
    while self.is_active==True:
        do it..
        if not self.is_active: return
        time.sleep(1)
        if not self.is_active: return
        do it..
        if not self.is_active: return
        time.sleep(1)
    
def Stop(self):
    self.is_active=False

python线程需要释放关联的资源,虽然可以使用一些C技巧“杀死”线程,但您将面临分段错误或内存泄漏的风险。
这里有一个更简洁的方法。

class MyError(Exception):
    pass
def Start(self):
    try:
        while self.is_active==True:
            do it..
            self.check_termination()
            time.sleep(1)
            self.check_termination()
            do it..
            self.check_termination()
            time.sleep(1)
    except MyError:
        return

def check_termination(self):
    if not self.is_active:
        raise MyError

并且可以从任何函数内部调用self.check_termination()来终止这个循环,而不必直接从Start内部调用。
编辑:ShadowRanger解决方案更好地处理了“可中断等待”,我只是保留了它,以便为线程实现一个kill开关,可以从线程内部的任何地方检查该开关。

相关问题