【问题标题】:PyQt GUI freezes until threads are finished while multithreading in PythonPyQt GUI 在 Python 中进行多线程时冻结,直到线程完成
【发布时间】:2015-04-19 22:32:11
【问题描述】:

代码很繁重,所以我将发布一些sn-ps。

class Program(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Program, self).__init__(parent)

...

def main():   
    app = QtGui.QApplication(sys.argv)
    global ex
    ex = Program()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

在这中间我有一堆标签、文本字段、按钮和 4 个 QListWidgets 在子布局中,这些子布局被添加到网格中。

我根据输入启动可变数量的线程。通常是 4 个线程。它们在自己的类中启动:

class myThread(Thread):
    def __init__(self, arguments, more_arguments):
        threading.Thread.__init__(self)

    def work_it(self, argument, more_arguments):
        Program.some_function_in_Program_class(ex, arguments)

然后我调用 Program() 类中的函数来对 GUI 进行实际更改。

Program.generate_results(ex, arguments, arguments2, more_arguments)

最后,它归结为一个我迭代的列表,以及我是打印每个元素还是使用:

my_listbox.addItem(item)

它会冻结 GUI,直到所有 4 个线程完成遍历列表。然后所有的结果一起出现,而不是一个一个出现。

我已在 Tkinter 中完成此操作,我可以看到列表项动态显示在 ListBox 小部件中,而不会冻结 GUI。

至于管理线程,我正在遍历一个列表并根据其长度创建多个线程:

threadlist = []
for i in self.results:
    sub_thread = myThread(i, self.results[i])
    self.threadlist.append(sub_thread)
swapAndWaitThread = spawnAndWaitThreadsThread(self.threadlist)
swapAndWaitThread.start()

我这样做是为了能够管理这 4 个线程并知道它们何时完成。

class spawnAndWaitThreadsThread(Thread):
    def __init__(self, threadlist):
        threading.Thread.__init__(self)
        self.threadlist = threadlist

    def run(self):
        for thread in self.threadlist:
            thread.start()

        for thread in self.threadlist:
            thread.join()

    print "threads finished.. do something"

我做错了什么?

【问题讨论】:

  • 不确定您是否知道这一点,但仅从Thread 继承不足以使一段代码成为多线程的。例如,对于从threading.thread 继承的线程,您需要将所需的代码放入其run 方法中,然后在某个时候调用start。出现在 __init__ 方法中的代码仍将在主线程中运行。
  • 感谢您的回复。这有点复杂。我已经更新了我的问题以回答您的评论。首先,我在我的 Program 类函数中列出线程。然后我将此列表发送到一个线程类,该线程类启动并加入线程,以便我可以找出所有线程何时完成。当这些线程启动(myThread 类)时,它们会在我想要更新我的 GUI 的 Program 类中再次调用一些函数。
  • 也许我从 Thread() 函数中错误地调用了 Program() 函数?我很挣扎,因为起初我试图通过简单的 Program.some_function(arguments).. 来调用它们,但不断收到关于程序实例未通过的错误。所以我不得不通过将“ex”声明为全局变量并将其作为 Program() 实例参数传递来提出一个肮脏的(?)修复。这是正确的做法吗?
  • 将程序实例添加到线程的“官方”方法是在线程的run 定义中添加一个参数并像thread.start(args = (my_program_instance,)) 一样启动线程,但是全局变量应该可以工作也。一般来说,您的spawnAndWaitThreadsThread 对我来说看起来不错。我认为我要寻找问题的下一个地方是myThread
  • 所以如果一个人浏览了成百上千个文件(os.path.listdir),通过一些扩展过滤它们,提取它们的时间戳,将结果连接到一个字符串,然后尝试写入一个将这数百个字符串动态分配给多个 QListWidget,它不应该冻结程序,对吧?

标签: python multithreading user-interface pyqt4 freeze


【解决方案1】:

我通过在只有一个工作的主 Program() 类中添加一个非常简单的函数来解决这个问题 - 启动一个非常简单的线程,该线程又返回到 Program() 类并在那里调用一个函数,然后启动构建我的线程列表,将它们发送到另一个线程类,等等。

因此,GUI 不再冻结。

【讨论】:

  • 没有得到。如果您无法输入实际代码,请举例说明
猜你喜欢
  • 2012-05-12
  • 2019-05-10
  • 1970-01-01
  • 2012-08-10
  • 2014-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多