2

我写了一个 Rhythmbox 插件,我正在尝试添加一些代码来异步下载一些 JSON。回调在do_activate函数中注册:

def do_activate(self):
    shell = self.object
    sp = shell.props.shell_player
    self.db = shell.get_property('db')
    self.qm = RB.RhythmDBQueryModel.new_empty(self.db)
    self.pec_id = sp.connect('playing-song-changed', self.playing_entry_changed)
    self.pc_id = sp.connect('playing-changed', self.playing_changed)
    self.sc_id = sp.connect('playing-source-changed', self.source_changed)
    self.current_entry = None

    ...

我正在尝试在playing_changed触发时下载一些内容。它目前用于urllib2同步下载内容,但这有可能会在短时间内阻塞 UI。我想使用 Twisted 来解决问题,但是我见过的所有示例都使用reactor.run(),它会无限期地阻塞。

我对 Twisted 很陌生,我想知道,有没有办法在不阻塞主线程的情况下异步处理这种情况?

完整代码在这里

4

2 回答 2

2

在不运行 IO-loop ( reactor.run) 的情况下,twisted 无法执行异步 http 请求。运行reactor使您能够使用默认情况下 python 中不存在的异步功能。但是,如果您使用twisted 的唯一原因是进行异步http 调用,那可能是一种矫枉过正。改用简单的线程,让你的线程等待 http 响应。

于 2012-10-18T11:25:53.190 回答
2

在 Rhythmbox 插件的上下文中,您可能需要处理 GTK 主循环已经在运行的事实。这是 Twisted 原则上支持的一种情况,但支持 API 以在可能已经或可能还没有主循环的主循环上协作初始化反应器是棘手的。

您可以使用以下函数解决它:

def maybeInstallReactor():
    import sys
    if 'twisted.internet.reactor' not in sys:
        from twisted.internet import gtk2reactor # s/2/3 if you're using gtk3
        reactor = gtk2reactor.install()
        reactor.startRunning()
        reactor._simulate()
    else:
        from twisted.internet import reactor
    return reactor

确保在您的程序中尽早调用此函数,然后再导入其他任何内容(尤其是来自 Twisted 的内容)。

startRunning调用将反应器连接到 GLib 主循环,并且该_simulate调用将 Twisted 的定时事件连接到 GLib 计时器。

遗憾的是,这确实涉及调用一个私有函数 ,_simulate因此您必须小心确保新版本的 Twisted 不会破坏它;但是由于这个问题,我打开了一个错误来明确支持这个用例。 另外,除了这个私有方法调用之外,关于你对 Twisted 的使用没有什么奇怪的了。

于 2012-10-19T06:40:02.227 回答