【问题标题】:wxpython threading textctrl delaywxpython线程textctrl延迟
【发布时间】:2013-08-31 22:33:08
【问题描述】:

我对 wxpython 的 textctrl 和线程有任何疑问。希望能帮助您解决此问题。

我的程序处理文件,当每个文件被处理时,它在 textctrl 中被列为已完成。当只处理几个文件时,textctrl 是响应式的并且会立即显示并且不会消失。即使这些文件很大。对一个 700mb 的文件进行了测试,textctrl 运行良好。

在处理许多文件时会出现问题,例如 20+。在这种情况下,textctrl 会消失 6 或 7 秒,然后重新出现并正常工作。

我尝试过普通线程、守护线程等。还尝试使用 .join(),这让事情变得更糟。我想知道这是否只是因为我的程序是处理器密集型的,或者我只是做错了什么。

下面列出了我的线程代码。到目前为止,这是迄今为止最快的方法,但对我的目的来说还不够好。在此先感谢克林顿。

def Worker(self, e, _file):

    match = ''

    with open(_file, 'r') as f:
        data = f.read()

    for char in data:
        if char in self.key:
            match += chr(self.key.index(char))

    open(_file, 'w').close()

    with open(_file, 'w') as f:
        f.write(match)

    wx.CallAfter(self.ListFilesEncrypt, e, _file)

if __name__ == '__main__':
    for _file in self.file2process:
        self.filenum += 1
        Thread(target=self.Worker, args=(e, _file,)).start()

【问题讨论】:

  • 如何从线程更新文本控件?如果是直接调用文本控件,那就有问题了
  • 你是说你正在创建多个线程来更新文本控件,可能一次?
  • 老实说,对于 python 和编程来说,我不确定是否真的很新。 The code above works but when a lot of files are selected to be processed the textctrl disappears for 6 seconds then reappears.一旦它重新出现,它就可以正常工作。在处理完每个文件后,它会打印到 textctrl 中。所以 textctrl 的输出类似于 linux ls 命令的输出。一旦打印开始,它就可以正常工作,只是最初的烦人延迟。
  • 我用代码示例更新了我的答案

标签: multithreading wxpython textctrl


【解决方案1】:

使用线程安全的方法更新 GUI。在wxPython中,有3个:

  • wx.CallAfter
  • wx.CallLater
  • wx.PostEvent

您还应该查看 wxPython wiki 以获取有关 wxPython 和线程的信息:

我还写了一篇关于这个主题的教程:

更新:这是一个简单的例子,它创建了 40 个线程和“进程”40 个组成的文件。当每个线程完成时,它会更新显示。但是,我没有看到您所说的问题。

import random
import time
import wx

from threading import Thread
from wx.lib.pubsub import Publisher

########################################################################
class TestThread(Thread):
    """Test Worker Thread Class."""

    #----------------------------------------------------------------------
    def __init__(self, fname, sleepAmt):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self.fname = fname
        self.sleepAmt = sleepAmt
        self.start()    # start the thread

    #----------------------------------------------------------------------
    def run(self):
        """Run Worker Thread."""
        # This is the code executing in the new thread.
        time.sleep(self.sleepAmt)
        msg = "%s finished in %s seconds!" % (self.fname, self.sleepAmt)
        wx.CallAfter(Publisher().sendMessage, "update", msg)


########################################################################
class MyForm(wx.Frame):

    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")

        panel = wx.Panel(self, wx.ID_ANY)
        self.updateText = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        self.btn = btn = wx.Button(panel, label="Start Thread")

        btn.Bind(wx.EVT_BUTTON, self.onButton)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.updateText, 1, wx.ALL|wx.EXPAND, 5)
        sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
        panel.SetSizer(sizer)

        # create a pubsub receiver
        Publisher().subscribe(self.updateDisplay, "update")

    #----------------------------------------------------------------------
    def onButton(self, event):
        """
        Runs the thread
        """
        for i in range(40):
            fname = "test%s.txt" % i
            secs = random.choice(range(3, 15))
            TestThread(fname, secs)

    #----------------------------------------------------------------------
    def updateDisplay(self, msg):
        """
        Receives data from thread and updates the display
        """
        data = msg.data + "\n"
        self.updateText.WriteText(data)

#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

我正在使用 Python 2.6 和 wxPython 2.8.12.1 在 Windows 7 上运行

【讨论】:

  • 感谢您的回复。应该提到我已经在使用 ww.CallAfter。我什至尝试将它全部删除,只是为了看看它有什么效果。即使不打印到 textctrl,也不要回答任何问题。它与选择进行处理的文件数量有关。克林顿。
  • 我已经编辑了问题并提供了工作线程函数的代码。
  • 感谢 Mike 提供的代码示例。您没有遇到与我相同的问题的原因很可能归结为您的代码与我的代码有些不同。我目前仍在处理我的第一个问题,目前大约有 300 行左右的代码,所以对我来说没有 Hello World :-) 我看起来像我将不得不再次重写(现在 5 或 6 次)以您的代码为例。与命令行程序相比,编写 GUI 程序有多么困难,这让我感到惊讶。对我来说,它的代码量增加了一倍,复杂性增加了三倍。再次感谢克林顿。
  • 是的,GUI 需要一段时间。但通过练习,你会变得更好、更快。
【解决方案2】:

您的线程应该不直接更新文本控件 - 他们应该使用 wx.CallAfter,或者更好的是,为主线程 (GIU) 设置一个标志更新控件 - 听起来像结束线程方法可能是合适的。

【讨论】:

  • 感谢您的回复。根据我对 Mike Driscoll 的回复,我已经在使用 wx.CallAfter,所以这不是问题所在。这更多地与已选择进行处理的文件数量有关。甚至删除了 wx.callafter,因此没有打印到 textctrl。仍然有同样的问题。不过,我会研究您的其他 2 条建议。克林顿。
【解决方案3】:

除了 CPU 密集型之外,它还可能是 IO 密集型。 IO 密集型应用程序会对性能产生非常大的影响,尤其是当您还将 IO 单元用于分页等其他关键目的时。我建议一次提供 5 到 10 份服务,其余的则排队。

【讨论】:

  • 感谢您的回复。之前尝试过一次队列但没有成功,但会再试一次。我对编程还是很陌生,所以可能会以某种方式搞砸。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-18
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 2023-03-11
  • 2011-07-12
  • 1970-01-01
相关资源
最近更新 更多