代码之家  ›  专栏  ›  技术社区  ›  balpha

pyqt应用程序中的线程:使用qt线程还是python线程?

  •  98
  • balpha  · 技术社区  · 15 年前

    我正在编写一个GUI应用程序,它通过Web连接定期检索数据。由于此检索需要一段时间,这会导致在检索过程中UI没有响应(不能拆分为较小的部分)。这就是为什么我要将Web连接外包到一个单独的工作线程。

    [是的,我知道,现在我有了 two problems ]

    无论如何,应用程序使用pyqt4,所以我想知道更好的选择是:使用qt的线程或使用python threading 模块?各有哪些优点/缺点?或者你有完全不同的建议?

    编辑(重新奖励): 在我的特殊情况下,解决方案可能会使用非阻塞网络请求,比如 Jeff Ober Lukáš Lalinský 建议(所以基本上把并发问题留给网络实现),我仍然希望对一般问题有一个更深入的答案:

    使用pyqt4(即qt)线程与本机python线程(来自 螺纹加工 模块?


    编辑2: 谢谢你的回答。尽管没有100%的一致意见,但似乎普遍认为答案是“使用qt”,因为它的优点是与库的其余部分集成,而不会造成真正的缺点。

    对于希望在两个线程实现之间进行选择的任何人,我强烈建议他们阅读这里提供的所有答案,包括Pyqt邮件列表线程 abbot 链接到。

    我为赏金考虑了几个答案;最后,我选择了方丈的,作为非常相关的外部参考;然而,这是一个非常接近的要求。

    再次感谢。

    7 回复  |  直到 8 年前
        1
  •  92
  •   abbot    13 年前

    这是 discussed 不久前在Pyqt邮件列表中。引用乔瓦尼·巴乔的话 comments 关于主题:

    基本上是一样的。主要的区别是qthreads更好 与Qt(异步信号/时隙、事件循环等)集成。 另外,不能从python线程使用qt(例如 通过qapplication.post event将事件发布到主线程):您 需要一个qthread才能工作。

    一般的经验法则可能是使用qthreads,如果您打算以某种方式与qt交互,则可以使用python线程。

    Pyqt的作者早些时候对此发表了评论:“它们都是同一个本机线程实现的包装器”。两种实现都以相同的方式使用gil。

        2
  •  31
  •   Jeff Ober    15 年前

    Python的线程将更简单、更安全,而且由于它是针对基于I/O的应用程序的,所以它们能够绕过gil。也就是说,您是否考虑过使用扭曲或非阻塞套接字/选择来实现非阻塞I/O?

    编辑:有关线程的详细信息

    蟒蛇线程

    python的线程是系统线程。但是,python使用全局解释器锁(gil)来确保解释器每次只执行一定大小的字节代码指令块。幸运的是,python在输入/输出操作期间释放gil,使线程对模拟非阻塞I/O很有用。

    重要警告: 这可能会产生误导,因为字节码指令的数目 对应于程序中的行数。即使是一个单独的分配在Python中也可能不是原子的,因此对于 任何 必须以原子方式执行的代码块,即使使用gil也是如此。

    Qt螺纹

    当python将控制权交给第三方编译的模块时,它将释放gil。模块有责任在需要时确保原子性。当控件返回时,Python将使用gil。这会使使用第三方库和线程混淆。更难使用外部线程库,因为它增加了模块与解释器之间控制在何时何地的不确定性。

    qt螺纹在释放gil的情况下工作。qt线程能够同时执行qt库代码(以及其他未获取gil的编译模块代码)。但是,在qt线程的上下文中执行的python代码 仍然 获得金边,现在你必须管理 用于锁定代码的逻辑集。

    最后,qt线程和python线程都是围绕系统线程的包装器。python线程使用起来稍微安全一些,因为那些不是用python编写的部分(隐式地使用gil)在任何情况下都使用gil(尽管上面的警告仍然适用)。

    非阻塞I/O

    线程给您的应用程序增加了异常的复杂性。尤其是在处理Python解释器和编译模块代码之间已经很复杂的交互时。虽然许多人发现基于事件的编程很难遵循,但是基于事件的、非阻塞的I/O通常比线程更难解释。

    对于异步I/O,您总是可以确保对于每个打开的描述符,执行路径是一致和有序的。显然,有一些问题必须解决,例如当依赖于一个开放通道的代码进一步依赖于另一个开放通道返回数据时要调用的代码的结果时,该怎么做。

    对于基于事件的、无阻塞的I/O,一个很好的解决方案是 Diesel 图书馆。目前它仅限于Linux,但速度非常快,而且相当优雅。

    这也是值得你花时间学习的 pyevent 这是一个极好的libevent库的包装器,它为基于事件的编程提供了一个基本框架,使用您的系统最快的可用方法(在编译时确定)。

        3
  •  21
  •   LukáÅ¡ Lalinský    15 年前

    的优势 QThread 它是与qt库的其余部分集成的。也就是说,qt中的线程感知方法需要知道它们在哪个线程中运行,并且要在线程之间移动对象,需要使用 Q螺纹 . 另一个有用的特性是在线程中运行自己的事件循环。

    如果要访问HTTP服务器,应考虑 QNetworkAccessManager .

        4
  •  13
  •   Natim    15 年前

    我在工作的时候也问过自己同样的问题 PyTalk .

    如果使用qt,则需要使用 QThread 能够使用qt框架,尤其是信号/时隙系统。

    使用信号/时隙引擎,您将能够从一个线程与另一个线程以及项目的每个部分进行对话。

    而且,这两个选择都不是一个性能问题,因为它们都是C++绑定。

    这是我对pyqt和thread的经验。

    我鼓励你使用 Q螺纹 .

        5
  •  9
  •   ekhumoro    8 年前

    杰夫有些优点。只有一个主线程可以进行任何GUI更新。如果您确实需要从线程中更新GUI,那么qt-4 queued connection 信号使跨线程发送数据变得容易,并且在使用qthread时将自动调用;我不确定在使用python线程时是否会调用这些信号,尽管在 connect() .

        6
  •  5
  •   p_l    15 年前

    我也不能推荐,但我可以尝试描述cpython和qt线程之间的区别。

    首先,cpython线程不会并发运行,至少不会运行python代码。是的,它们确实为每个python线程创建系统线程,但是只允许运行当前持有全局解释器锁的线程(C扩展和FFI代码可能会绕过它,但不执行python字节码,而线程不持有gil)。

    另一方面,我们有qt线程,它基本上是系统线程的公共层,没有全局解释器锁,因此能够并发运行。我不确定Pyqt是如何处理它的,但是,除非您的qt线程调用python代码,否则它们应该能够并发运行(禁止在各种结构中实现各种额外的锁)。

    对于额外的微调,您可以修改在切换gil之前解释的字节码指令的数量-较低的值意味着更多的上下文切换(并且可能更高的响应性),但每个线程的性能较低(上下文切换有其成本-如果您尝试每隔几条指令切换一次,这没有帮助速度。

    希望它能帮助你解决问题。)

        7
  •  0
  •   brianz    15 年前

    我不能评论python和pyqt线程之间的确切区别,但我一直在使用 QThread , QNetworkAcessManager 一定要打电话 QApplication.processEvents() 当线程处于活动状态时。如果您要解决的问题是GUI响应, the later 会有帮助的。