Python DBus中的异步方法实现

5 投票
1 回答
2743 浏览
提问于 2025-04-15 18:30

我该如何在Python的DBus中实现一个异步方法呢?下面是一个例子:

class LastfmApi(dbus.service.Object):
    def __init__(self):
        bus_name = dbus.service.BusName('fm.lastfm.api', bus=dbus.SessionBus())
        dbus.service.Object.__init__(self, bus_name, '/')

    @dbus.service.method('fm.last.api.account', out_signature="s")
    def getUsername(self):
        ## How do I get this method done asynchronously ??
        ##  For example, this method should go off and retrieve the "username"
        ##  asynchronously. When this method returns, the "username" isn't available
        ##  immediately but will be made available at a later time.

我正在使用Twisted的glib2反应器。

更新:我知道这种行为是可以实现的 - DBus为方法调用提供了一个“序列号”(唯一标识符),被调用的方法可以使用这个标识符来将“调用”和“回复”进行匹配。

1 个回答

6

我没有尝试过这个,但看了下关于 dbus.service.method 的文档,发现里面有一个 async_callbacks 参数。这个参数听起来是用来提供异步结果的。比如:

@dbus.service.method('fm.last.api.account', out_signature="s",
                     async_callbacks=("callback", "errback"))
def getUsername(self, callback, errback):
    reactor.callLater(3, callback, "alice")

如果你有一个返回了 Deferred 的 API,那么你可以很容易地把这个 Deferred 和这些回调函数关联起来:

d.addCallbacks(callback, errback)

至于调用和响应之间的关系,我猜所有的序列号处理都是隐藏在 dbus.service.method 里面的。我怀疑当你使用 async_callbacks 功能时传入的回调和错误回调函数,要么是某个可以调用的类的实例,并且有序列号这个属性,要么就是定义为嵌套函数,并且能够访问到序列号。这样,当你调用其中一个函数时,它们就能确保把正确的值传回连接,以便将响应和最初的请求关联起来。

不过,这只是基于你提到的序列号和我在实现各种异步系统时的经验,稍微有点知识的猜测。:) 如果能看看 dbus.service.method 的实现,可能会更清楚实际的策略,而不会太费劲。

(好吧,我实际上去看了一下实现,结果发现它相当复杂,当代码涉及到 C 级的 dbus 绑定时,我就跟不上了,这比我想做的要深入得多。我仍然怀疑我上面描述的总体思路是正确的,但实现的细节比我预期的要复杂得多。)

撰写回答