【问题标题】:Using PyQt with gevent将 PyQt 与 gevent 一起使用
【发布时间】:2011-01-07 17:25:43
【问题描述】:

有人在 gevent 中使用过 PyQt 吗? 如何将 PyQt 循环链接到 gevent?

http://www.gevent.org/ - 基于协程的 Python 网络库,使用 greenlet 在 libevent 事件循环之上提供高级同步 API。

【问题讨论】:

  • 什么是“gevent”?请为您的问题添加链接。
  • gevent.org - 基于协程的 Python 网络库,使用 greenlet 在 libevent 事件循环之上提供高级同步 API。
  • 非常有趣.. pyqt + gevent 工作时你会做什么?
  • 我需要使用gevent线程,因为必须异步使用db和network。我不能用 QThreads 使用的 python 线程来做到这一点。

标签: python pyqt gevent


【解决方案1】:

您可以使用 Qt IDLE“计时器”来允许 gevent 在短时间内(例如 10 毫秒)不处理任何 Qt 事件时处理其微线程。它仍然不完美,因为它没有提供“最平滑”的可能集成。这是因为我们没有为 Qt 和 gevent 使用单个事件循环,只是及时“交错”它们。

正确的解决方案是允许 libevent 以某种方式监听新的 Qt 事件,但我还没有弄清楚如何在实践中做到这一点。当 GUI 事件到达事件队列时,让 Qt 通过套接字向 gevent 发送一些东西可能会有所帮助。有人解决了吗?

工作示例:

""" Qt - gevent event loop integration using a Qt IDLE timer
"""

import sys, itertools

import PySide
from PySide import QtCore, QtGui

import gevent

# Limit the IDLE handler's frequency while still allow for gevent
# to trigger a microthread anytime
IDLE_PERIOD = 0.01

class MainWindow(QtGui.QMainWindow):

    def __init__(self, application):

        QtGui.QMainWindow.__init__(self)

        self.application = application

        self.counter = itertools.count()

        self.resize(400, 100)
        self.setWindowTitle(u'Counting: -')

        self.button = QtGui.QPushButton(self)
        self.button.setText(u'Reset')
        self.button.clicked.connect(self.reset_counter)

        self.show()

    def counter_loop(self):

        while self.isVisible():
            self.setWindowTitle(u'Counting: %d' % self.counter.next())
            gevent.sleep(0.1)

    def reset_counter(self):

        self.counter = itertools.count()

    def run_application(self):

        # IDLE timer: on_idle is called whenever no Qt events left for processing
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.on_idle)
        self.timer.start(0)

        # Start counter
        gevent.spawn(self.counter_loop)

        # Start you application normally, but ensure that you stop the timer
        try:
            self.application.exec_()
        finally:
            self.timer.stop()

    def on_idle(self):

        # Cooperative yield, allow gevent to monitor file handles via libevent
        gevent.sleep(IDLE_PERIOD)

def main():

    application = QtGui.QApplication(sys.argv)
    main_window = MainWindow(application)
    main_window.run_application()

if __name__ == '__main__':
    main()

【讨论】:

    【解决方案2】:

    我尝试了以下方法:为 gevent 提供“PyQt 后端”,即。使用 QSocketNotifier、QTimer 等 PyQt 构造的 gevent 循环的实现,而不是 libev 循环。最后我发现它比做相反的要容易得多,而且性能非常好(Qt的循环是基于Linux下的glib,还不错)。

    这里是 github 上的项目链接,供感兴趣的人使用: https://github.com/mguijarr/qtgevent

    这只是一个开始,但它适用于我所做的测试。如果对 gevent 和 PyQt 有更多经验的人可以做出贡献,我会很高兴。

    【讨论】:

      【解决方案3】:

      以下是通过示例的 session1 更改 pyqt 以进行协作的方法:https://github.com/traviscline/pyqt-by-example/commit/b5d6c61daaa4d2321efe89679b1687e85892460a

      【讨论】:

      • 它很容易在没有任何有用活动的情况下导致 100% 的 CPU 负载,因为您没有使用大于零的 gevent.sleep 周期。
      • 在 greenlet 中运行 Qt 事件循环效果不佳,我遇到了 seg 错误,并且在打开模式对话框时它会阻塞。
      【解决方案4】:

      你应该避免使用 app.exec_(),它是一个循环函数,它使用这个函数来处理事件:

      http://doc.qt.nokia.com/stable/qcoreapplication.html#processEvents

      所以你可以直接调用 processEvents。

      【讨论】:

      • 在没有任何活动的情况下很容易导致100%的CPU负载。
      【解决方案5】:

      我发布了一个名为eventlet-pyqt 的项目。我希望它对想要在他们的 PyQt 应用程序中使用 greenlet 的人有用。我也尝试过 gevent,但由于我的 C 语言经验不佳,我很难为 libevent 编写插件。使用QApplicaton::processEvents() 或零间隔QTimer 的主要问题是,程序运行到无限循环,导致100% 的CPU 核心使用率。为了避免这种情况,我编写了一个新的集线器来用 PyQt 的 QSocketNotifier 替换 select() 函数。希望这条消息可以帮助一些人。

      【讨论】:

        猜你喜欢
        • 2020-07-12
        • 2011-05-03
        • 2014-02-01
        • 1970-01-01
        • 2019-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多