bal*_*pha 107 python multithreading pyqt
我正在编写一个GUI应用程序,它定期通过Web连接检索数据.由于此检索需要一段时间,因此会导致UI在检索过程中无响应(无法将其拆分为较小的部分).这就是为什么我想将Web连接外包给一个单独的工作线程.
[是的,我知道,现在我有两个问题.]
无论如何,应用程序使用PyQt4,所以我想知道更好的选择是什么:使用Qt的线程还是使用Python threading模块?每个的优点/缺点是什么?或者你有一个完全不同的建议?
编辑(重新赏金):虽然在我的特定情况下的解决方案可能会使用像Jeff Ober和LukášLalinský建议的非阻塞网络请求(所以基本上将并发问题留给网络实现),我仍然喜欢更多对一般问题的深入回答:
使用PyQt4(即Qt)线程优于本机Python线程(来自threading模块)的优点和缺点是什么?
编辑2:谢谢大家的答案.虽然没有100%的协议,但似乎普遍认为答案是"使用Qt",因为它的优点是与库的其余部分集成,同时没有造成任何真正的缺点.
对于任何想要在两个线程实现之间进行选择的人,我强烈建议他们阅读这里提供的所有答案,包括abbot链接到的PyQt邮件列表线程.
我考虑了赏金的几个答案; 最后,我选择了abbot作为非常相关的外部参考; 然而,这是一个近距离的电话.
再次感谢.
abb*_*bot 101
不久前在PyQt邮件列表中讨论过这个问题.引用Giovanni Bajo 对此主题的评论:
它大致相同.主要区别在于QThreads与Qt(异步信号/时隙,事件循环等)更好地集成.此外,您不能使用Python线程中的Qt(例如,您不能通过QApplication.postEvent将事件发布到主线程):您需要一个QThread来实现它.
一般的经验法则可能是使用QThreads,如果你要以某种方式与Qt进行交互,否则使用Python线程.
还有一些早先对PyQt作者对此主题的评论:"它们都是围绕相同本机线程实现的包装器".两种实现都以相同的方式使用GIL.
Jef*_*ber 32
Python的线程将更简单,更安全,并且由于它适用于基于I/O的应用程序,因此它们可以绕过GIL.也就是说,您是否考虑过使用Twisted或非阻塞套接字/ select的非阻塞I/O?
编辑:更多关于线程
Python线程
Python的线程是系统线程.但是,Python使用全局解释器锁(GIL)来确保解释器一次只执行一定大小的字节码指令块.幸运的是,Python在输入/输出操作期间释放GIL,使线程可用于模拟非阻塞I/O.
重要提示:这可能会产生误导,因为字节码指令的数量与程序中的行数不对应.即使单个赋值在Python中也可能不是原子的,因此对于必须以原子方式执行的任何代码块都需要互斥锁,即使使用GIL也是如此.
QT线程
当Python将控制权移交给第三方编译模块时,它会释放GIL.模块的责任是在需要时确保原子性.当传回控件时,Python将使用GIL.这可能会使第三方库与线程混淆使用.使用外部线程库更加困难,因为它增加了模块与解释器控制的位置和时间的不确定性.
QT线程在GIL发布的情况下运行.QT线程能够同时执行QT库代码(以及其他未获取GIL的编译模块代码).然而,QT线程的上下文中执行的Python代码仍然取得GIL,现在你必须要管理2台逻辑的锁定你的代码.
最后,QT线程和Python线程都是围绕系统线程的包装器.Python线程使用起来比较安全,因为那些不是用Python编写的部分(隐式使用GIL)在任何情况下都使用GIL(尽管上面的警告仍然适用).
非阻塞I/O.
线程为您的应用程序增加了极大的复杂性.特别是在处理Python解释器和编译模块代码之间已经很复杂的交互时.虽然许多人发现难以遵循基于事件的编程,但基于事件的非阻塞I/O通常比线程更难以推理.
使用异步I/O,您始终可以确保对于每个打开的描述符,执行路径是一致且有序的.显然,必须解决一些问题,例如当依赖于一个开放通道的代码进一步依赖于在另一个开放通道返回数据时要调用的代码的结果时该怎么做.
基于事件的非阻塞I/O的一个很好的解决方案是新的Diesel库.目前它仅限于Linux,但它非常快速且非常优雅.
值得花时间学习pyevent,这是一个很棒的libevent库的包装器,它为使用最快的系统方法(在编译时确定)提供基于事件的编程的基本框架.
Luk*_*ský 21
它的优点QThread是它与Qt库的其余部分集成在一起.也就是说,Qt中的线程感知方法需要知道它们在哪个线程中运行,并且要在线程之间移动对象,您需要使用QThread.另一个有用的功能是在线程中运行自己的事件循环.
如果您正在访问HTTP服务器,则应该考虑QNetworkAccessManager.
我也不能真正推荐,但我可以尝试描述CPython和Qt线程之间的差异.
首先,CPython线程不会同时运行,至少不是Python代码.是的,他们确实为每个Python线程创建了系统线程,但是只允许当前持有Global Interpreter Lock的线程运行(C扩展和FFI代码可能绕过它,但是当线程不保持GIL时不执行Python字节码).
另一方面,我们有Qt线程,它们基本上是系统线程上的公共层,没有Global Interpreter Lock,因此能够并发运行.我不确定PyQt如何处理它,但是除非你的Qt线程调用Python代码,否则它们应该能够并发运行(禁止可能在各种结构中实现的各种额外锁).
对于额外的微调,您可以修改在切换GIL的所有权之前解释的字节码指令的数量 - 较低的值意味着更多的上下文切换(可能更高的响应性),但每个单独的线程的性能更低(上下文切换有其成本 - 如果您尝试切换每一条指令,它无助于速度.)
希望它有助于你的问题:)