我有一个现有的程序,它有自己的主循环,并根据它收到的输入进行计算 - 让我们说来自用户,使其变得简单。我想现在远程而不是本地进行计算,我决定在Twisted中实现RPC。
理想情况下,我只想更改我的一个函数,比如doComputation()
来调用twisted来执行RPC,获取结果并返回。程序的其余部分应该保持不变。但是我怎么能做到这一点呢?当我呼叫reactor.run()
时,Twisted劫持主循环。我还读到你没有扭曲的线程,所有的任务按顺序运行,所以我似乎不能创建一个LoopingCall并以这种方式运行我的主循环。
答案 0 :(得分:8)
您有几个不同的选项,具体取决于您现有程序的主循环类型。
如果它是GUI库的主循环,Twisted may already have support for it。在这种情况下,您可以继续使用它。
您也可以编写自己的反应堆。没有很多很好的文档,但是you can look at the way that qtreactor在Twisted外部实现了一个reactor插件。
您还可以使用threadedselectreactor
编写最小反应堆。此文档也很稀疏,但the wxpython reactor是使用它实现的。我个人不推荐这种方法,因为它很难测试并且可能导致混乱的竞争条件,但它确实具有让你几乎只使用几乎所有Twisted的默认网络代码的优势包裹层。
如果您确定不希望doComputation
异步,并希望程序在等待Twisted应答时阻止,请执行以下操作:
twistedThread = Thread(target=reactor.run); twistedThread.start()
RPCDoer
),这样你就可以引用它了。确保使用reactor.callFromThread
实际启动其Twisted逻辑,这样您就不需要包装所有Twisted API调用。RPCDoer.doRPC
以返回Deferred(即不要调用现有的应用程序代码,因此您无需担心应用程序对象的线程安全性;将doRPC
所需的所有信息作为参数传递。您现在可以像这样实施doComputation
:
def doComputation(self):
rpcResult = blockingCallFromThread(reactor, self.myRPCDoer.doRPC)
return self.computeSomethingFrom(rpcResult)
reactor.callFromThread(reactor.stop); twistedThread.join()
,否则您可能会在退出时看到一些令人困惑的回溯或日志消息。最后,你应该考虑一个选项,特别是从长远来看:转储你现有的主循环,找出一种方法来使用Twisted。根据我的经验,对于像这样的问题的10个问题中的9个,这是正确的答案。我并不是说这是始终的方式 - 有很多情况下你真的需要保持自己的主循环,或者只是需要付出过多的努力来摆脱它现有的循环。但是,保持自己的循环也是有效的。请记住,Twisted循环已经被数百万用户广泛测试,并在各种环境中使用。如果你的循环也非常成熟,那可能不是什么大问题,但如果你正在编写一个小的新程序,可靠性的差异可能会很大。
答案 1 :(得分:1)
这里似乎正确且非常简单的答案是LoopingCall:
http://www.saltycrane.com/blog/2008/10/running-functions-periodically-using-twisteds-loopingcall/
from datetime import datetime
from twisted.internet.task import LoopingCall
from twisted.internet import reactor
def doComputation():
print "Custom fn run at", datetime.now()
lc = LoopingCall(doComputation)
lc.start(0.1) # run your own loop 10 times a second
# put your other twisted here
reactor.run()