在PyQt中使用gevent

10 投票
5 回答
3524 浏览
提问于 2025-04-16 09:35

有没有人用过PyQt和gevent一起?怎么把PyQt的循环和gevent连接起来?

http://www.gevent.org/ - 这是一个基于协程的Python网络库,它使用greenlet来提供一个高级的同步接口,建立在libevent事件循环之上。

5 个回答

4

我尝试了以下方法:为gevent创建一个“PyQt后端”,也就是说,使用PyQt的一些组件,比如QSocketNotifier、QTimer等,来实现gevent的循环,而不是使用libev循环。最后我发现这样做比反过来要简单得多,而且性能也很好(Qt的循环在Linux下是基于glib的,表现还不错)。

对于感兴趣的人,这里有项目的github链接: https://github.com/mguijarr/qtgevent

这只是个开始,但在我做的测试中效果很好。如果有更有经验的人在gevent和PyQt方面能够贡献一些意见,我会很高兴。

6

你可以使用Qt的一个“定时器”来让gevent处理它的小线程,这样在一段时间内(比如10毫秒)没有Qt事件被处理时,它就能工作。不过,这种方法并不是最完美的,因为它没有做到最流畅的整合。原因在于,我们没有为Qt和gevent使用同一个事件循环,而是让它们在时间上交替进行。

正确的解决方案应该是让libevent能够监听新的Qt事件,但我还没有找到实际操作的方法。也许可以让Qt在GUI事件进入事件队列时,通过一个套接字发送一些信息给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

这里是如何修改 pyqt by example 的 session1 以实现协作的步骤:https://github.com/traviscline/pyqt-by-example/commit/b5d6c61daaa4d2321efe89679b1687e85892460a

撰写回答