【问题标题】:Role of Mainloops, Event Loops in DBus serviceDBus服务中Mainloops、Event Loops的作用
【发布时间】:2016-01-30 10:55:08
【问题描述】:

这是DBus服务的标准示例。

import dbus
import gobject
from dbus import service
# from gi._gobject import MainLoop
from dbus.mainloop.glib import DBusGMainLoop

class DBusServer(service.Object):
    def __init__(self, name, object_path):
        # super(service.Object, self).__init__(name, object_path)
        dbus.service.Object.__init__(self, name, object_path)

    @dbus.service.method("com.test", in_signature='s', out_signature="s")
    def test(self, args):
        return args + " Sent by dbus client"

    @dbus.service.method("com.test", in_signature='s', out_signature="s")
    def foo(self, args):
        return "foo"

bus_loop = DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
session_name = service.BusName("com.test", session_bus)
dbus_server = DBusServer(session_name, "/test")

loop = gobject.MainLoop()

try:
    loop.run()
except KeyboardInterrupt:
    loop.quit()

我对这里使用的两个主循环有疑问
1.这段代码中每个主循环或事件循环的作用是什么(如果我使用正确的术语。我猜它们都是事件循环)
2. 如果我的应用程序不是 GUI 应用程序,为什么我需要 gobject mainloop 或 qt mainloop,因为这是从 X11 库中捕获用户生成的事件所必需的(在 Linux 的情况下)
3. 为什么我不能用一个什么都不做的无限循环来代替gobject主循环(如下)

while True:
    pass

【问题讨论】:

  • 我已经更新了我的答案,以尝试更好地解释其中涉及的概念。希望能帮助到你。 (另外,如果有帮助,请接受答案:))

标签: python python-3.x dbus pyqt5


【解决方案1】:

以下是总结的简短答案,更多解释请参见末尾的详细信息。

问题 1:

您发布的代码中只使用了一个主循环,loop = gobject.MainLoop()。它的作用是处理事件,例如D-Bus 消息发送到您的服务。

问题 2:

您需要一个主循环,以便您的代码不会阻止来自您的服务之外的 D-Bus 消息。 dbus-python 绑定没有主循环实现,因此您需要使用其他库中的主循环(也需要dbus-python 支持,在本例中为 GLib)。

问题 3:

这样的无限循环将永远不允许执行除该特定循环之外的任何代码,并且无法接收 D-Bus 消息(或任何其他事件)。

详情:

简单地说,当您的程序中当前没有代码运行时,主循环通常会处理其他事件。在这种情况下,D-Bus 的性质要求您的代码有一种方法来处理来自外部源的事件,即 D-Bus 消息。这就是你需要一个主循环的原因。您可以将事件处理基于您自己编写的循环,只要循环中有可以处理外部事件的代码。人们经常将库用于主循环的原因是因为在“真实”应用程序或系统中事情往往会变得复杂,并且使用已经被其他人测试、使用和改进多年的东西(例如 GLib)通常更健壮。

D-Bus 绑定dbus-python 的实现方式需要使用外部主循环,因为它没有自己的主循环实现。将库设计为使用外部主循环的一个典型原因是让库的用户决定使用哪个主循环,因为主循环也可能用于其他事情(例如处理 D-Bus 事件之外的其他事件)。这增加了库的潜在使用并减少了作为使用库的副作用而引入的依赖项。

然而,该库必须支持所选的主循环,这意味着必须为每个打算与该库一起使用的主循环专门提供一些集成。通常,像这样的库的内部将被设计为使用作为 mainloop 抽象的类/类型,因此代码内部不需要知道已集成的 mainloop。这减少了需要在库中特定于 mainloop 实现的代码量。

如果您检查在执行操作时收到的bus_loop 对象:

bus_loop = DBusGMainLoop(set_as_default=True)

...您将看到它是dbus.mainloop.NativeMainLoop 类型的对象,它是dbus-python 中的主循环包装对象。

现在,dbus-python 目前只为 GLib 主循环提供集成,因此在这种情况下,上面的讨论变得有点理论化了。 dbus-python 集成 GLib 主循环的方式是要求用户导入并实例化 GLib 主循环包装器,如下所示:

from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)

这会创建一个 GLib 主上下文,稍后 GLib 主循环将使用该主上下文来处理 dbus-python 与该上下文相关联的事件。主循环集成的最后一部分是要求用户启动一个 GLib 主循环。当您导入并运行gobject 主循环时,如下所示:

loop = gobject.MainLoop()
loop.run()

主循环将处理先前创建的上下文中的事件。这是 D-Bus 绑定 dbus-python 和 GObject 绑定 gobject(它可以访问 GLib 主循环)之间的“链接”。

简化到极致,可以说是在做的时候创建和设置的上下文:

from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)

是一个事件列表,如果它们出现则要处理,主循环在执行时创建和启动:

loop = gobject.MainLoop()
loop.run()

是什么让某些东西检查该列表。简单地说,GLib 用于这两个方面的事实使它可以工作。

如果您想进一步深入研究,请阅读 GLib 和 GMainLoop 和 GMainContext 以及与这些相关的概念。希望这会有所帮助。

【讨论】:

  • 感谢您的回答。它清除了一些东西。如果我正确理解了您的答案,我可以说 gobject.Mainloop() 包含侦听 DBus 生成的事件的代码,即 gobject.Mainloop() 已明确提供对 DBus 的支持。
  • 我猜 dbus-python 在使用时会检查它是否是“默认主循环”,在这种情况下,它之前设置为 GLib。所以 dbus-python 集成了 GLib 主循环,并且知道如何挂钩,因此 GLib 主循环通过调用 dbus-python 来处理 D-Bus 事件。所以它仍然是 dbus-python 做 D-Bus 工作,但它使用 GLib 来调用事件。从这个意义上说,dbus-python 提供了对 GLib 的支持,而不是相反。将 D-Bus 和主循环创建分开的一个原因是,您可能希望在同一程序中也将主循环用于其他事情。
猜你喜欢
  • 2014-10-31
  • 2010-09-20
  • 2019-04-21
  • 2016-03-12
  • 1970-01-01
  • 2010-11-28
  • 2013-10-27
  • 2017-05-07
  • 1970-01-01
相关资源
最近更新 更多