K.M*_*ier 6 python multithreading python-3.x
我更喜欢在不考虑图形用户界面的情况下编写我的应用程序。一旦应用程序代码正常工作,我喜欢在它上面粘贴一个 GUI 层——两者之间有一个干净的界面。
我首先尝试使 GUI 在与应用程序不同的进程中运行。但我很快就后悔了那个实验。在两个进程之间建立通信链接绝非易事。所以我决定现在,多线程没问题(尽管 Python Global Interpreter Lock 使它们在单个内核上运行)。
该MainThread完全是在Qt的图形用户界面的手中。显然这是标准做法。所以让我们假设软件的整体结构应该是这样的(注意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')
Run Code Online (Sandbox Code Playgroud)
这个选择在我看来是最干净的。您可以真正编写您的appThread代码,而无需考虑 GUI。毕竟,您使用的是标准 Pythonthreading库。那里没有 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,...
我的建议是做大多数其他人所做的事情。等到有代码需要在单独的线程中运行时,然后只将那段代码放在一个线程中。您的代码无需位于单独的线程中即可实现良好的代码分离。我会这样做的方式如下:
将您的appThread代码(不了解 GUI 的代码)放在仅了解非 GUI 库的基类中。这使得以后也可以轻松支持代码的命令行版本。将需要异步执行的代码放入该基类的常规 Python 线程中。确保您想要异步执行的代码只是一个函数调用,以便更容易理解我的下一点。
然后,在一个单独的文件中创建一个子类,该子类继承您刚刚编写的基类和 QMainWindow 类。任何需要异步运行的代码都可以通过 QThread 类调用。如果您像我上面提到的那样,在一个函数调用中使想要异步运行的代码可用,那么很容易使此步骤适用于您的 QThread 子类。
为什么要进行上述操作?
它使管理状态和通信变得更加容易。为什么在不必要的时候让自己因竞争条件和线程通信而发疯呢?实际上,在 GUI 中为应用程序代码和 GUI 代码设置单独的线程也没有任何性能原因,因为大多数时候,就 CPU 而言,用户实际上并没有输入太多内容。只有速度慢的部分才应该放入线程中,这样既可以保持理智,又可以使代码管理更容易。另外,对于 Python,由于 GIL,您无法从单独的线程中获得任何东西。
| 归档时间: |
|
| 查看次数: |
1136 次 |
| 最近记录: |