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

应用程序线程和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之间。我的第一个问题是,如果其中一个是臭名昭著的事件调度线程。这两个线程在堆栈跟踪的底部都有以下内容: 我认为问题的根源在于应用程序类将域数据与图

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

  • 我已经阅读了一些基于这个主题的注释,虽然我对线程有了一般的理解,但我并不确定用户级线程和内核级线程之间的区别。 我知道进程基本上由多个线程或单个线程组成,但这些线程是前面提到的两种类型吗? 据我所知,内核支持的线程可以访问内核进行系统调用和其他用户级线程不可用的用途。 那么,用户级线程仅仅是程序员在使用内核支持的线程执行由于其状态而不能正常执行的操作时创建的线程吗?