如何从插件调用Twisted到已经运行主循环的GTK程序?

时间:2012-10-18 11:09:37

标签: python asynchronous twisted rhythmbox

我写了一个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同步下载内容,但这有可能在短时间内阻止用户界面。我想使用Twisted来解决问题,但我见过的所有例子都使用reactor.run(),它会无限期地阻塞。

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

完整代码为here

2 个答案:

答案 0 :(得分:2)

在没有运行IO-loop(reactor.run)的情况下,没有任何方法可以进行异步http请求。运行reactor使您可以使用默认情况下不存在于python中的异步功能。但是,如果您使用twisted的唯一理由是进行异步http调用,则可能是一种过度杀伤力。改为使用简单的线程,让你的线程等待http响应。

答案 1 :(得分: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的新版本不会破坏它; but as a result of this question I opened a bug to make this use-case explicitly supported.另外,除了这个私有方法调用之外,没有其他关于你使用Twisted的内容需要很奇怪。