我更喜欢在不考虑图形用户界面的情况下编写应用程序。一旦应用程序代码正常工作,我就想在它上面粘贴一个GUI层 - 两者之间有一个干净的接口。
我首先尝试在应用程序中使用不同的进程运行GUI。但我很快后悔那个实验。在两个进程之间建立通信链接远非微不足道。所以我决定,目前,多个线程都很好(尽管Python Global Interpreter Lock使它们在单个核心上运行)。
MainThread 完全掌握在Qt GUI手中。显然这是标准做法。因此,让我们假设软件的整体结构应如下所示(请注意 qtThread 与 MainThread 同义):
我的应用程序代码在 appThread 中运行 - 与GUI完全分开。但在某些时候,必须有互动。
我读过许多关于如何组织这篇文章的文章,但很多来源互相矛盾。根据许多人的说法,即使官方的Qt应用程序也是错误的(官方文档鼓励将QThread子类化)。我能找到的最具启发性的文章是:
http://ilearnstuff.blogspot.be/2012/08/when-qthread-isnt-thread.html http://ilearnstuff.blogspot.be/2012/09/qthread-best-practices-when-qthread.html
即使在考虑了所有这些之后,我仍然对几件事情保持怀疑。
问题1.启动 appThread 的最正确方法是什么?
启动 appThread 的最正确方法是什么?如果我错了,请纠正我,但我相信有两种选择:
选择1:启动标准Python线程
Python提供了threading
库,可以导入以生成新线程:
import threading
if __name__ == '__main__':
# 1. Create the qt thread (is MainThread in fact)
qtApp = QApplication(sys.argv)
QApplication.setStyle(QStyleFactory.create('Fusion'))
# 2. Create the appThread
appThread = threading.Thread(name='appThread', target=appThreadFunc, args=(p1,p2,))
appThread.start()
# 3. Start the qt event loop
qtApp.exec_()
print('Exiting program')
这个选择看起来对我来说最干净。您甚至可以在不考虑GUI的情况下真正编写 appThread 代码。毕竟,您正在使用标准的Python threading
库。那里没有Qt的东西。
但是我找不到关于在 appThread 和 MainThread 之间建立通信链接的明确文档。更多关于第二个问题中的问题..
选择2:启动QThread主题
这个选择看起来不那么干净,因为你不得不乱用Qt来编写你的应用程序代码。无论如何,它看起来是一个可行的选择,因为两个线程之间的通信链接 - appThread 和 MainThread - 可能更好地得到支持。
有很多方法可以启动QThread线程。鼓励官方Qt文档继承QThread
并重新实现run()方法。但我读到这种做法实际上非常糟糕。请参阅我在问题开头发布的两个链接的更多信息。
问题2.两个线程之间的最佳通信链接是什么?
两个线程之间最好的通信链接是什么?显然,这个问题的答案在很大程度上取决于问题1 中的选择。我可以想象,将标准Python线程链接到GUI与链接QThread有很大的不同 我会留给你提出建议,但我想到的一些机制是:
注意:
请提及您的答案是否适用于Python 2.x或3.x.还要记住,在谈论线程,队列等时,可能会很快出现混淆。如果您引用标准Python线程或QThread,标准Python队列或QQueue,请提及......
答案 0 :(得分:1)
我建议做其他人做的事情。等到有代码需要在一个单独的线程中运行,然后只将这段代码放在一个线程中。您的代码不需要在单独的线程中以实现良好的代码分离。我这样做的方法如下:
在只具有非GUI库知识的基类中拥有 appThread 代码(不了解GUI的代码)。这样,以后也可以轻松支持代码的命令行版本。将需要执行的代码异步执行到此基类的常规Python线程中。确保您想要异步执行的代码只是一个函数调用,以便我的下一个点更容易。
然后,将一个子类放在一个单独的文件中,该文件继承了刚刚编写的基类和QMainWindow类。您需要异步运行的任何代码都可以通过QThread类调用。如果您在上面提到的一个函数调用中创建了想要异步运行的代码,那么很容易让这个步骤适用于您的QThread子类。
为什么选择上述内容?
它使很多更容易管理状态和通信。为什么在没有必要的情况下让自己变得疯狂的竞争条件和线程沟通?对于应用程序代码与GUI代码,在GUI中使用单独的线程也没有性能原因,因为大多数时候用户实际上并没有输入太多CPU。只有缓慢的部分才能放入线程中,既可以节省成本,又可以简化代码管理。另外,使用Python,由于GIL,你无法从单独的线程中获得任何东西。