如何快速获取所有VLC实例的dbus?
基本上,问题是,要获取所有的VLC实例,唯一的方法就是搜索所有没有名字的实例,找到它们的org.freedesktop.MediaPlayer身份函数并调用它。
(另外,我可以使用反射API,但这似乎并不能解决我的问题)不幸的是,很多程序在发送dbus调用后,根本不响应,这会导致很长的超时等待。
当这种情况发生多次时,时间就会累积起来。总的来说,内置的超时时间太长了。
如果我能以某种方式减少dbus的超时时间,那就能解决我的问题,但理想的解决方案是找到一种方法。
我想到可以把每次调用“Identify”放在一个线程里,这样如果某个线程耗时太长就可以结束它,但这似乎并不是推荐的做法。而且,增加多线程会大幅提高CPU的负担,但并没有显著提高程序的速度。
这是我正在尝试让它快速运行的代码(或多或少),目前运行得非常慢。
import dbus
bus = dbus.SessionBus()
dbus_proxy = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
names = dbus_proxy.ListNames()
for name in names:
if name.startswith(':'):
try:
proxy = bus.get_object(name, '/')
ident_method = proxy.get_dbus_method("Identity",
dbus_interface="org.freedesktop.MediaPlayer")
print ident_method()
except dbus.exceptions.DBusException:
pass
1 个回答
1
比起创建很多线程,更简单的方法是让不同的服务异步调用,也就是在请求服务时提供一个回调处理程序,这样当结果返回或者出现错误时就能处理。所有的调用实际上是同时进行的,你的程序可以在收到一些有效结果后就继续运行。
下面是一个简单的程序,它会打印出找到的所有服务的列表。你会注意到,它能很快得到所有有效的结果,而不需要等待任何超时。在一个真正的程序中,你可能会给错误处理程序分配一个什么都不做的函数,因为你的目标是忽略那些没有响应的服务,但这个例子会等到所有服务都回应后才结束。
#! /usr/bin/env python
import dbus
import dbus.mainloop.glib
import functools
import glib
class VlcFinder (object):
def __init__ (self, mainloop):
self.outstanding = 0
self.mainloop = mainloop
bus = dbus.SessionBus ()
dbus_proxy = bus.get_object ("org.freedesktop.DBus", "/org/freedesktop/DBus")
names = dbus_proxy.ListNames ()
for name in dbus_proxy.ListNames ():
if name.startswith (":"):
proxy = bus.get_object (name, "/")
iface = dbus.Interface (proxy, "org.freedesktop.MediaPlayer")
iface.Identity (reply_handler = functools.partial (self.reply_cb, name),
error_handler = functools.partial (self.error_cb, name))
self.outstanding += 1
def reply_cb (self, name, ver):
print "Found {0}: {1}".format (name, ver)
self.received_result ()
def error_cb (self, name, msg):
self.received_result ()
def received_result (self):
self.outstanding -= 1
if self.outstanding == 0:
self.mainloop.quit ()
if __name__ == "__main__":
dbus.mainloop.glib.DBusGMainLoop (set_as_default = True)
mainloop = glib.MainLoop ()
finder = VlcFinder (mainloop)
mainloop.run ()