Использование PyQt с Gevent - PullRequest
9 голосов
/ 07 января 2011

Кто-нибудь использовал PyQt с gevent?Как связать цикл PyQt с gevent?

http://www.gevent.org/ - сетевая библиотека Python на основе сопрограмм, которая использует greenlet для обеспечения высокоуровневого синхронного API поверх цикла событий libevent.

Ответы [ 5 ]

4 голосов
/ 27 ноября 2011

Вы можете использовать "таймер" Qt IDLE, чтобы разрешить gevent обрабатывать свои микропотоки, в то время как события Qt не обрабатывались в течение короткого периода времени, например, 10 миллисекунд. Это все еще не идеально, так как это не дает "самой гладкой" возможной интеграции. Это потому, что мы не используем один цикл обработки событий как для Qt, так и для Gevent, а просто «чередуем» их во времени.

Правильным решением было бы позволить libevent как-то прослушивать новые события Qt, но я пока не смог понять, как это сделать на практике. Возможно, поможет использование Qt для отправки чего-либо в gevent через сокет, когда в очередь событий поступает событие GUI. Кто-нибудь решил это?

Рабочий пример:

""" 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()
3 голосов
/ 02 октября 2013

Я попробовал следующий подход: иметь «PyQt backend» для gevent, т.е.реализация цикла gevent с использованием конструкций PyQt, таких как QSocketNotifier, QTimer и т. д. вместо цикла libev.Наконец, я обнаружил, что это намного проще, чем делать обратное, и производительность очень хорошая (цикл Qt основан на glib под Linux, он не так уж и плох).

Вот ссылка на проект на github для интересующихся: https://github.com/mguijarr/qtgevent

Это только начало, но оно хорошо работает для тестов, которые я сделал.Я был бы счастлив, если бы люди с большим опытом работы с Gevent и PyQt могли внести свой вклад.

2 голосов
/ 16 февраля 2011

Вот как вы могли бы изменить pyqt для примера сеанса1 для сотрудничества: https://github.com/traviscline/pyqt-by-example/commit/b5d6c61daaa4d2321efe89679b1687e85892460a

1 голос
/ 27 августа 2013

Я выпустил проект с именем eventlet-pyqt .Я надеюсь, что это может быть полезно для тех, кто хочет использовать greenlet в своем приложении PyQt.Я также попробовал gevent, но мне было трудно написать плагин для libevent из-за моего плохого опыта в языке Си.Основная проблема с использованием QApplicaton::processEvents() или нулевого интервала QTimer заключается в том, что программа, запущенная в бесконечном цикле, вызывает 100% использование ядра ЦП.Чтобы избежать этого, я написал новый хаб, чтобы заменить функцию select() на PyQt QSocketNotifier.Надеюсь, это сообщение кому-нибудь поможет.

1 голос
/ 17 января 2011

Вы должны избегать использования app.exec_ (), это функция цикла, которая использует эту функцию для обработки событий:

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

, поэтому вы можете напрямую вызывать processEvents.*

...