<p>您有几个不同的选项,这取决于您现有程序的主循环类型。在</p>
<p>如果它是来自GUI库的主循环,<a href="http://twistedmatrix.com/documents/current/core/howto/choosing-reactor.html" rel="noreferrer">Twisted may already have support for it</a>。在这种情况下,你可以继续使用它。在</p>
<p>你也可以自己写反应堆。关于这一点没有很多好的文档,但是<a href="http://github.com/ghtdak/qtreactor" rel="noreferrer">you can look at the way that qtreactor</a>在Twisted外部实现了一个reactor插件。在</p>
<p>您也可以使用<code>threadedselectreactor</code>编写一个最小的reactor。这方面的文档也很少,但是<a href="http://twistedmatrix.com/trac/browser/tags/releases/twisted-10.1.0/twisted/internet/wxreactor.py#L60" rel="noreferrer">the wxpython reactor</a>是使用它实现的。就我个人而言,我不推荐这种方法,因为它很难测试并且可能会导致混乱的竞争条件,但是它确实有一个优点,可以让您利用Twisted的所有默认网络代码,只需一层薄薄的包装。在</p>
<p>如果您确实确定不希望<code>doComputation</code>是异步的,并且希望程序在等待Twisted应答时阻塞,请执行以下操作:</p>
<ul>
<li>在主循环启动之前在另一个线程中开始Twisted,使用类似<code>twistedThread = Thread(target=reactor.run); twistedThread.start()</code></li>
<li>在你自己的主循环线程中实例化一个对象来进行RPC通信(比如,<code>RPCDoer</code>),这样你就有了对它的引用。请确保使用<a href="http://twistedmatrix.com/documents/10.1.0/api/twisted.internet.interfaces.IReactorThreads.callFromThread.html" rel="noreferrer">^{<cd5>}</a>启动它的Twisted逻辑,这样就不需要包装它所有的Twisted API调用。在</li>
<li>实现<code>RPCDoer.doRPC</code>以返回一个<a href="http://twistedmatrix.com/documents/10.1.0/api/twisted.internet.defer.Deferred.html" rel="noreferrer">Deferred</a>,只使用扭曲的API调用(即,不要调用现有的应用程序代码,因此您不必担心应用程序对象的线程安全;将<code>doRPC</code>所需的所有信息作为参数传递)。在</li>
<li><p>现在可以如下实现<code>doComputation</code>:</p>
<pre><code>def doComputation(self):
rpcResult = blockingCallFromThread(reactor, self.myRPCDoer.doRPC)
return self.computeSomethingFrom(rpcResult)
</code></pre></li>
<li>记住从主循环的关闭过程调用<code>reactor.callFromThread(reactor.stop); twistedThread.join()</code>,否则在退出时可能会看到一些令人困惑的回溯或日志消息。在</li>
</ul>
<p>最后,一个你应该真正考虑的选择,特别是从长远来看:抛弃你现有的主循环,找出一个只使用Twisted的方法。以我的经验,这是10个问题中有9个是正确答案。我并不是说这永远是一个好方法,在很多情况下,你真的需要保留你自己的主循环,或者只是太多的努力来摆脱现有的循环。但是,维护自己的循环也是一项工作。请记住,Twisted loop已经过数百万用户的广泛测试,并在各种各样的环境中使用。如果您的循环也非常成熟,这可能不是什么大问题,但是如果您正在编写一个小的、新的程序,那么可靠性的差异可能会非常大。在</p>