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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With