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



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

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.is_active时,它才能终止。self.Stop(). 我在另一个自定义对象(计数器)中有相同的情况,当另一个线程(主线程)工作时,它们必须一起工作。

代码工作,但我意识到与进度条和计数器相关联的两个线程不会像我想要的那样立即终止,因为在终止之前,它们需要等待它们的函数结束,这些线程很慢,因为time.sleep(1)指令。从用户的角度来看,这意味着看到主线程结束的进度条和计数器终止LATE,我不喜欢它。

老实说,我不知道如何解决这个问题。是否有一种方法可以强制线程立即终止而无需等待函数结束?

首先,要清楚,硬杀死线程在任何语言中都是一个糟糕的想法,Python不支持它;如果不出意外,该线程持有一个从未解锁的锁,导致任何试图获取该锁的线程死锁,这是一个致命的缺陷。

如果你根本不在乎这个线程,你可以用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()

不冒分段错误风险的最安全的方法是返回。

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线程需要释放相关的资源,而"kill "使用一些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内部调用。

编辑:shadowwranger解决方案处理"可中断等待";更好的是,我只是为了实现线程的终止开关,可以从线程内的任何地方检查。

最新更新