wxPython OnExit()不停止线程?
我正在尝试创建一个线程,并在wxPython应用程序的框架关闭时结束它。这是我的密码:wxPython OnExit()不停止线程?,python,multithreading,wxpython,Python,Multithreading,Wxpython,我正在尝试创建一个线程,并在wxPython应用程序的框架关闭时结束它。这是我的密码: #! /usr/bin/env python import time, wx from threading import Thread class UpdateThread(Thread): def __init__(self): self.stopped = False Thread.__init__(self) def run(self):
#! /usr/bin/env python
import time, wx
from threading import Thread
class UpdateThread(Thread):
def __init__(self):
self.stopped = False
Thread.__init__(self)
def run(self):
while not self.stopped:
self.updateExchange()
time.sleep(1)
def updateExchange(self):
print("Updated...")
class tradeWindow(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, "Exchange", size = (500, 190))
panel = wx.Panel(self)
def OnExit(self):
tickThread.stopped # I've also tried: tickThread.stopped = True
tickThread = UpdateThread()
tickThread.start()
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = tradeWindow(parent = None, id = -1)
frame.Show()
app.MainLoop()
但是当我关闭框架时,它会继续打印。在
tickThread.start()之前尝试设置tickThread.setDaemon(True)
-应该与其父线程一起退出。没有神奇的frame.OnExit
方法。你把框架和应用程序搞混了。与其他窗口一样,框架也会关闭。应用程序退出
因此,您可以将代码放在应用程序类的OnExit
方法中。但这不是你想要的
查看OnExit
方法。同样,这不是您想要的,但是您应该知道它是如何工作的(以及它被调用的对象)
您始终可以绑定EVT\u CLOSE
在窗口中调用任何您想要的内容。但你必须明确地做到这一点
通常,您会调用方法OnClose
或OnCloseWindow
。将其称为OnExit只会导致严重的混乱(正如它所做的那样)
绑定到的事件处理程序方法实际上必须是一个事件处理程序,这意味着它接受一个事件
参数(以及自身
)
接下来,如果您添加一个EVT\u CLOSE
处理程序,您将覆盖默认处理程序,这意味着除非您自己这样做,否则永远不会调用Destroy
下面是关于bindingEVT\u CLOSE
,其中显示了上述所有步骤
最后,正如DavidRobinson所解释的,仅仅做tickThread.stopped
不会做任何事情;您必须将其设置为True
总而言之:
class tradeWindow(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, "Exchange", size = (500, 190))
panel = wx.Panel(self)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, event):
tickThread.stopped = True
self.Destroy()
另请注意:
在任何严肃的线程程序中,如果希望在线程之间共享值,通常需要将其与某种同步对象同步。如果您正在等待来自另一个线程的信号,典型的处理方法是使用。另一方面,如果您只想共享该值,则可以使用
如果您真的知道自己在做什么,通常可以让全局解释器锁为您处理同步。但总的来说,这是个坏主意。例如,您的主线程可能在核心0上运行,而您的后台线程可能在核心1上运行,Python语言定义中没有任何东西可以保证计算机将更新后的值从核心0的缓存复制到核心1。因此,您的背景线程可能会永远旋转,观察旧值,而永远不会看到新值。事实证明,在x86上使用CPython 2.0-3.3时,您的代码不可能出现这种情况,但如果您能证明(或至少确定安全的情况),就不要指望它了
最后,您询问了守护进程线程是否是合适的解决方案。发件人:
此标志的意义在于,当只剩下守护进程线程时,整个Python程序将退出
换句话说,您的程序可以退出,而无需停止守护进程线程。但是
注意:守护进程线程在关机时突然停止。他们的资源(如打开的文件、数据库事务等)可能无法正常释放。如果希望线程正常停止,请将其设为非守护进程,并使用合适的信号机制,如事件
tickThread.stopped=True
显然更接近解决方案(tickThread.stopped
永远不会做任何事情)。你试过在OnExit
中放一个打印语句以确保它被调用吗?@DavidRobinson它没有被调用,很奇怪……我必须检查一下,但我认为wx.Frame
没有OnExit
;这是wx.App
。根据一些谷歌搜索,我认为你的\uuuu init\uuuuuu
中缺少了一行:self.Bind(wx.EVT\u CLOSE,self.OnExit)
(请在我作为答案发布之前试一试)@DavidRobinson我在\uu init\uuuuuu
的末尾添加了这句话,当我按下关闭按钮时,我得到了TypeError:OnExit()正好接受1个参数(给定2个)
。我给OnExit()添加了一个无用的参数,现在它运行OnExit()函数,但不关闭窗口。到目前为止,它似乎很完美,但有什么缺点吗?@tkbx:如果你想完全关闭,你不能这样做。如果你不在乎清洁关机,这是一个简单的解决办法。@abarnert“清洁关机”到底是什么意思?OnClose
方法手动处理所有事情,而不是将工作传递给Python?@tkbx:Daemon线程没有完全关闭,它们只是在某个任意点停止运行。如果您想确保它们已经完成,或者释放一些系统资源,或者刷新对文本文件或数据库的写入,这样它们就不会丢失,那么您不能这样做。阅读中的第一个注释。另外,您确实不应该调用setDaemon
。这在2.x中是“旧的”,在3.x中是“不推荐的”。正如文档所说,只需直接设置守护进程
属性。