Python Twisted:如何调度?
我在Twisted上有一天的经验,想要安排在回复TCP客户端时发送消息:
import os, sys, time
from twisted.internet import protocol, reactor
self.scenario = [(1, "Message after 1 sec!"), (4, "This after 4 secs"), (2, "End final after 2 secs")]
for timeout, data in self.scenario:
reactor.callLater(timeout, self.sendata, data)
print "waited %d time, sent %s\n"%(timeout, data)
现在消息可以发送了,但我遇到了两个问题:
1) “超时”是从“现在”开始计算的,我希望在每个前一个任务完成后再开始计时(也就是前一条消息发送完后再计时)
2) 我不知道在所有消息发送完后怎么关闭连接。如果我把 self.transport.loseConnection()
放在 callLater
后面,它会立刻关闭连接。
在之前的尝试中,我没有使用 reactor.callLater
,而是只用 self.transport.write()
和 time.sleep(n)
在 for
循环中。这种情况下,所有消息是在所有超时结束后一起发送的……这并不是我想要的。
我的目的是等待客户端连接,等待超时1后发送消息1,等待超时2后发送消息2,依此类推。最后一条消息发送完后再关闭连接。
2 个回答
这个交易的最终解决方案..
import os, sys, time
from twisted.internet import protocol, reactor
import itertools
def sendScenario(self):
def sendelayed(d):
self.sendata(d)
self.factory.out_dump.write(d)
try:
timeout, data = next(self.sc)
reactor.callLater(timeout, sendelayed, data)
except StopIteration:
print "Scenario completed!"
self.transport.loseConnection()
self.scenario = [(1, "Message after 1 sec!"), (4, "This after 4 secs"), (2, "End final after 2 secs")]
self.sc = iter(self.scenario)
timeout, data = next(self.sc)
reactor.callLater(timeout, sendelayed, data)
在使用Twisted时,有一点很重要,那就是什么都不会等待。当你调用reactor.callLater()
时,你是在告诉反应器去稍后执行某个操作,而不是现在。这个调用会立刻完成(也就是在安排好这个调用后,还没执行的时候)。因此,你的print
语句其实是个谎言:你并没有等待timeout
的时间;你根本没有等待。
你可以用多种方法来解决这个问题,具体用哪种方法取决于你想要的效果。如果你希望第二个任务在第一个任务开始后四秒再开始,你可以简单地把第一个任务的延迟(你的timeout
变量)加到第二个任务的延迟上。不过,第一个任务可能不会在你安排的时间准确开始;如果Twisted太忙,它可能会晚点开始。而且,如果你的任务耗时较长,第二个任务可能在第一个任务完成之前就开始了。
更常见的做法是让第一个任务去安排第二个任务,而不是立刻安排第二个任务。你可以在第一个任务结束后四秒再安排第二个任务(在第一个任务结束时调用reactor.callLater()
),或者在第一个任务开始时四秒后再安排(在第一个任务开始时调用reactor.callLater()
),或者进行更复杂的计算来决定它应该何时开始,同时记录经过的时间。
当你意识到在Twisted中什么都不会等待时,处理完成所有安排的任务后关闭连接就变得简单了:你只需让最后一个任务调用self.transport.loseConnection()
。对于更复杂的情况,你可能想把Deferred
连接在一起,或者使用DeferredList
来在所有待处理任务完成后执行loseConnection()
,即使这些任务并不是严格按顺序执行的。