简单地使用线程来更新GUI还不够吗?

时间:2011-11-29 15:15:35

标签: python multithreading thread-safety wxpython

例如:

class DemoFrame(wx.Frame):

    def __init__(self):
        Initializing
        ...
        self.TextA = wx.StaticText(MainPanel, id = -1, label = "TextAOrWhatever")
        self.TextB = wx.StaticText(MainPanel, id = -1, label = "TextBOrWhatever")
        ...

    def StaticTextUpdating(self, ObjectName, Message):
        ObjectName.SetLabel(Message)

    def WorkerA(self):
        while True:
            Work on something

            UpdatingThread = threading.Thread(target = self.StaticTextUpdating, args = (self.TextA, "Something for TextA", ))
            UpdatingThread.start()

            time.sleep(randomSecs)

    def WorkerB(self):
        while True:
            Work on something

            UpdatingThread = threading.Thread(target = self.StaticTextUpdating, args = (self.TextB, "Something for TextB", ))
            UpdatingThread.start()

            time.sleep(randomSecs)

    ...

    def StartWorking(self):
        Spawn WorkerA thread
        Spawn WorkerB thread
        ...

正如您所看到的,我总是在新线程中更新StaticText,并且我在任何特定时间点100%确定只有一个线程更新特定对象,但问题是,现在每个然后运行一段时间后,一些物体就消失了。为什么会这样?这是否意味着GUI更新不是线程安全的?也许在某个时间点只能更新一个对象?

加了:

好的,wx.CallAfter应该是上述代码的一个很好的解决方案。但我还有另一个问题,如果按钮事件和SetLabel同时发生怎么办?这样的事情不会引起麻烦,虽然我没有看到吗?

2 个答案:

答案 0 :(得分:4)

大多数wx方法都不是线程安全的。如果要从另一个线程调用wx方法,请使用wx.CallAfter;取代

ObjectName.SetLabel(Message)

使用:

wx.CallAfter(ObjectName.SetLabel, Message)

编辑:一些背景信息

在wx(以及大多数其他UI平台)中,所有UI更新都在称为主线程(或UI线程)的单个线程中执行。这是为了通过避免线程同步的性能损失来使UI更快地工作。

但缺点是,如果我们编写代码来从不同的线程更新UI,则结果是未定义的。有时它可能会起作用,有时它可能会崩溃,有时可能会发生其他一些事情。所以我们应该总是去UI线程来进行UI更新。因此我们使用CallAfter函数在UI线程中执行UI更新功能。

UI thread in java

UI thread in C#

答案 1 :(得分:2)

要记住的主要事情是你不应该在不使用线程安全方法的情况下更新wxPython中的任何内容,例如wx.CallAfter,wx.CallLater或wx.PostEvent。有关详细信息,请参阅http://wiki.wxpython.org/LongRunningTaskshttp://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/