سؤال

Does anyone used PyQt with gevent? How to link PyQt loop to the gevent?

http://www.gevent.org/ - coroutine-based Python networking library that uses greenlet to provide a high-level synchronous API on top of libevent event loop.

هل كانت مفيدة؟

المحلول

Here's how you would change pyqt by example's session1 to cooperate: https://github.com/traviscline/pyqt-by-example/commit/b5d6c61daaa4d2321efe89679b1687e85892460a

نصائح أخرى

You can use a Qt IDLE "timer" to allow gevent for processing its microthreads while no Qt events handled for a short period of time, for example 10 milliseconds. It is still not perfect, since it does not give the "smoothest" possible integration. It is because we don't use a single event loop for both Qt and gevent, just "interleaving" them in time.

The correct solution would be to allow libevent to listen on new Qt events somehow, but I haven't been able to figure out how to do that in practice yet. Maybe having Qt to send something to gevent via a socket when a GUI event arrives into the event queue would help. Has anybody solved that?

Working example:

""" 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()

I tried the following approach: to have a "PyQt backend" for gevent, ie. an implementation of the gevent loop making use of PyQt constructs like QSocketNotifier, QTimer, etc. instead of the libev loop. Finally I found it much easier than doing the opposite, and performance is very good (Qt's loop is based on the glib under Linux, it's not so bad).

Here is the link to the project on github for those interested: https://github.com/mguijarr/qtgevent

This is just a start, but it works well for the tests I did. I would be happy if people with more experience with gevent and PyQt could contribute.

you sould avoid use app.exec_(), it is a loop function which use this function to process events:

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

so you can call processEvents directly.

I released a project named eventlet-pyqt. I hope it could be useful for the one who want to use greenlet in their PyQt application. I also tried gevent, but it was difficult for me to write a plugin for libevent because of my poor C language experience. The main problem using QApplicaton::processEvents() or a zero-interval QTimer is, the program run into infinite loop, causes 100% CPU core usage. To avoid this, I wrote a new hub to replace the select() function with PyQt's QSocketNotifier. Hope this message could help some one.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top