当前位置: 首页 > 知识库问答 >
问题:

应用程序线程和Qt线程之间的清晰分离(Python-PyQt)

奚和光
2023-03-14

我更喜欢编写我的应用程序,甚至不考虑图形用户界面。一旦应用程序代码正常工作,我喜欢在它上面粘合一个图形用户界面层——两者之间有一个干净的界面。

我首先尝试让GUI在不同于应用程序的进程中运行。但是我很快就后悔了那个实验。在两个进程之间建立通信链路绝非小事。所以我决定现在,多线程是可以的(尽管Python全局解释器锁使它们在单个核心上运行)。

主线程完全掌握在QtGUI手中。显然,这是标准做法。因此,让我们假设软件的整体结构如下所示(请注意,qtThread与MainThread同义):

我的应用程序代码运行在appThread中,与GUI完全分离。但在某种程度上,必须有互动。

我读过很多关于如何组织这方面的文章,但许多来源相互矛盾。许多人认为,即使是官方的Qt应用程序也是错误的(官方文档鼓励将QThread子类化)。我能找到的最有启发性的文章如下:

即使在考虑了所有这些之后,我仍然对一些事情持怀疑态度。


问题1。启动appThread最合适的方法是什么

启动appThread最合适的方法是什么?如果我错了,请纠正我,但我相信有两种选择:

选择1:启动一个标准的Python线程
Python提供了一个可以导入来生成新线程的线程库:

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代码。毕竟,您使用的是标准的Pythonthreading库。里面没有Qt的东西
但是我找不到关于在appThread和主线程之间设置通信链接的清晰文档。在第二个问题中有更多关于这个问题的信息。。

选择2:启动一个QThread线程
这个选择看起来不太干净,因为你必须弄乱Qt的东西来写你的应用程序代码。无论如何,它看起来是一个可行的选择,因为两个线程之间的通信链接——appThread和Main Thread——可能得到了更好的支持。
有无数种方法可以启动QThread线程。官方Qt留档鼓励子类QThread并重新实现run()方法。但是我读到这种做法实际上非常糟糕。有关更多信息,请参阅我在问题开始时发布的两个链接。


问题二。两个线程之间最好的通信链接是什么?

两个线程之间最好的通信链接是什么?显然,这个问题的答案在很大程度上取决于问题1中的选择。我可以想象,将一个标准的Python线程链接到图形用户界面与链接一个QThread有很大的不同。
我会让你提出建议,但是我脑海中突然出现的几个机制是:

  • 队列:使用标准Python队列还是Qt队列


注释:

请说明你的答案是否适用于Python 2. x或3. x。还要记住,当谈到线程、队列等时,混乱可能会很快出现。请注意,如果您指的是标准Python线程或QThread,标准Python队列或QQueue,...

共有1个答案

马奇略
2023-03-14

我的建议是做大多数人都做的事。等到有代码需要在一个单独的线程中运行,然后只将这段代码放在一个线程中。您的代码不需要位于单独的线程中,就可以实现良好的代码分离。我的做法如下:

将appThread代码(不了解GUI的代码)放在只了解非GUI库的基类中。这使得以后也很容易支持命令行版本的代码。将需要异步执行的代码放入该基类的常规Python线程中。确保要异步执行的代码只是一个函数调用,以便于我的下一点。

然后,在一个单独的文件中创建一个子类,该子类继承自您刚刚编写的基类和QMainWindow类。任何需要异步运行的代码都可以通过QThread类调用。如果像我前面提到的那样,在一个函数调用中使要异步运行的代码可用,那么很容易使此步骤适用于QThread子类。

为什么会出现上述情况?

它使管理状态和通信变得更加容易。为什么要让自己在比赛条件和线程通信中变得疯狂?对于应用程序代码和图形用户界面代码,在图形用户界面中使用单独的线程也是没有性能原因的,因为大多数时候用户实际上并没有像CPU那样输入太多。只有慢的部分应该放在线程中,这样既可以节省理智,又可以使代码管理更容易。另外,使用Python,由于GIL,你不会从单独的线程中获得任何东西。

 类似资料:
  • 问题内容: 我正在编写一个GUI应用程序,该应用程序通过Web连接定期检索数据。由于此检索需要一段时间,因此这会导致UI在检索过程中无响应(无法拆分成较小的部分)。这就是为什么我想将Web连接外包给一个单独的工作线程。 [是的,我知道,现在我有两个问题。] 无论如何,该应用程序使用PyQt4,所以我想知道更好的选择是:使用Qt的线程还是使用Python threading模块?各自的优点/缺点是什

  • 本文向大家介绍进程和线程之间的区别,包括了进程和线程之间的区别的使用技巧和注意事项,需要的朋友参考一下 进程是活动程序,即正在执行的程序。它不仅包含程序代码,还包括程序计数器,进程堆栈,寄存器,程序代码等。与此相比,程序代码只是文本部分。 线程是可以由调度程序独立管理的轻量级进程。它使用并行性提高了应用程序性能。线程与它的对等线程共享信息,如数据段,代码段,文件等,而该线程包含其自己的寄存器,堆栈

  • 问题内容: 如何区分正在运行的Java线程和本机线程? 在Linux中,每个子进程都有一个父进程,他们说0是所有进程的父进程,所有分叉的Java线程中都会有一个父线程吗? 我如何知道哪个Java线程与OS线程相关(如果Java线程派生了本机进程线程)。 Java线程和OS线程有任何命名约定吗? 可以从另一个Java代码中挂起或杀死正在运行的Java线程吗? 问题答案: 在Linux上,Java线程

  • 问题内容: 我在维护的Swing应用程序中遇到了僵局,尽管我有一个可行的解决方法,但我不确定我是否了解自己在做什么,还没有隐藏可能弹出的竞争条件稍后再试。 线程跟踪显示死锁发生在两个线程AWT-EventQueue-0和AWT- EventQueue-1之间。我的第一个问题是,如果其中一个是臭名昭著的事件调度线程。这两个线程在堆栈跟踪的底部都有以下内容: 我认为问题的根源在于应用程序类将域数据与图

  • 我正在考虑从主线程创建、的可能性,而分离的线程创建线程并等待之后再运行下一个线程。 但我不认为这是可能的,因为我总是在第一个线程之后而在下一个线程之前崩溃。 : : 因此,以下是我希望发生的事情: 更新:如何接受这个并将其分解,以便在标头中声明,但在需要的地方执行,然后执行

  • 问题内容: 在阅读了这个答案和Robert Love的“LinuxKernelDevelopment”之后,随后在系统调用中,我发现Linux中的进程和线程(几乎)与内核没有区别。它们之间有一些调整(在引用的SO问题中被讨论为“更多共享”或“更少共享”),但是我仍然有一些问题需要解答。 我最近开发了一个包含几个POSIX线程的程序,并决定在此前提下进行试验。在创建两个线程的进程中,所有线程当然都会