使用自己的主循环在Twisted中

6

我有一个现有程序,它有自己的主循环,并根据接收到的输入进行计算 - 简单起见,假设是来自用户的输入。现在我想远程执行这些计算,而不是本地执行,并决定使用Twisted实现RPC。

理想情况下,我只想更改其中一个函数,比如doComputation(),以调用Twisted执行RPC,获取结果并返回。程序的其余部分应该保持不变。但是,我该如何实现呢?当我调用reactor.run()时,Twisted会劫持主循环。我还读到,在Twisted中没有真正的线程,所有任务都按顺序运行,因此似乎无法只创建LoopingCall并以这种方式运行我的主循环。

2个回答

8

根据您现有程序的主循环类型,您有几种不同的选择。

如果它是来自GUI库的主循环,则Twisted可能已经支持它。在这种情况下,您可以直接使用它。

您还可以编写自己的反应器。虽然这方面的文档不多,但您可以查看qtreactor如何将反应器插件外部化到Twisted中。

您也可以使用threadedselectreactor编写最小的反应器。虽然这方面的文档也很少,但wxpython反应器就是使用它实现的。个人不建议采用此方法,因为它难以测试,并可能导致混乱的竞争条件,但它确实具有让您利用几乎所有Twisted默认网络代码的优点,只需要薄薄的包装层。

如果您确信不想让您的doComputation异步执行,并且希望在等待Twisted回答时阻塞程序,请按照以下步骤操作:

  • start Twisted in another thread before your main loop starts up, with something like twistedThread = Thread(target=reactor.run); twistedThread.start()
  • instantiate an object to do your RPC communication (let's say, RPCDoer) in your own main loop's thread, so that you have a reference to it. Make sure to actually kick off its Twisted logic with reactor.callFromThread so you don't need to wrap all of its Twisted API calls.
  • Implement RPCDoer.doRPC to return a Deferred, using only Twisted API calls (i.e. don't call into your existing application code, so you don't need to worry about thread safety for your application objects; pass doRPC all the information that it needs as arguments).
  • You can now implement doComputation like this:

    def doComputation(self):
        rpcResult = blockingCallFromThread(reactor, self.myRPCDoer.doRPC)
        return self.computeSomethingFrom(rpcResult)
    
  • Remember to call reactor.callFromThread(reactor.stop); twistedThread.join() from your main-loop's shutdown procedure, otherwise you may see some confusing tracebacks or log messages on exit.

最后,有一个选项你应该真正考虑,特别是从长远来看:抛弃现有的主循环,找出一种方法只使用Twisted的主循环。根据我的经验,对于10个问题提问者中的9个人来说,这是正确的答案。我并不是说这总是正确的方式 - 有很多情况下,你确实需要保留自己的主循环,或者消除现有循环太费力了。但是,维护自己的循环也是需要工作的。请记住,Twisted循环已经被数百万用户广泛测试,并在各种环境中使用。如果您的循环也非常成熟,那可能并不重要,但如果您正在编写一个小型的新程序,可靠性的差异可能会很大。


2
感谢您提供的出色答案!我倾向于采用倒数第二种方法,但我会考虑替换我的主循环。现在,将Twisted运行在单独的线程中与将其作为主线程运行并使用reactor.callInThread()调用我的主循环相比,有什么好处吗? - Claudiu
阻塞线程调用是正确的方式。 - Claudiu

1

1
没有实际阅读,我能在60秒内让它工作。现在需要找出性能和副作用,但对我来说已经满足需求了。 - Angry 84

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接