将 PyQt 与 gevent 结合使用

发布于 2024-10-10 13:28:15 字数 198 浏览 4 评论 0原文

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

素手挽清风 2024-10-17 13:28:17

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

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.

不再让梦枯萎 2024-10-17 13:28:16

您可以使用 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()

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()
梦里兽 2024-10-17 13:28:16

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

对于感兴趣的人来说,这是 github 上该项目的链接:
https://github.com/mguijarr/qtgevent

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

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.

¢好甜 2024-10-17 13:28:16

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

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

梦屿孤独相伴 2024-10-17 13:28:16

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

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

这样你就可以直接调用processEvents。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文