Python扭曲:如何安排?
具有扭曲的为期1天的经验,我尝试安排消息回复发送到TCP客户端:Python扭曲:如何安排?
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)
现在,它发送的消息,但我有2个问题:
1)“超时”是从去“现在“,并且我想在每个前一个任务完成之后对其进行计数(之前的消息已发送)
2)我不知道如何在所有消息发送后关闭连接。如果我在callLater
之后放置self.transport.loseConnection()
,它立即关闭连接。
在之前的尝试中,我没有使用reactor.callLater
,但只有self.transport.write()
和time.sleep(n)
在for
循环中。在这种情况下,所有消息在所有超时过后都会一起发送......不是我想要的。
目的是等待客户端连接,等待timeout1并发送message1,等待timeout2并发送message2,等等。最后的消息 - 关闭连接之后。
与Twisted一起工作时要认识到的重要一点是什么也没有等到。当您致电reactor.callLater()
时,您要求反应堆稍后拨打,而不是现在。该通话立即结束(通话结束后,已执行之前)。因此,您的print
声明是谎言:您没有等待timeout
时间;你根本没有等。
您可以通过多种方式解决问题,使用哪个取决于您实际需要的内容。如果您希望第二个任务在第一个任务开始后四秒开始,您可以简单地将第一个任务的延迟(您的timeout
变量)添加到第二个任务的延迟中。不过,第一项任务可能无法准确开始,它可能会在稍后开始,如果Twisted太忙,无法尽快启动它。此外,如果您的任务需要很长时间,则在第二个任务开始之前可能不会完成任务。
更常见的方法是让第一个任务安排第二个任务,而不是马上安排第二个任务。您可以在第一个任务结束后四秒(通过在第一个任务结束时调用reactor.callLater()
)或第一个任务开始后四秒钟(通过在第一个任务的开始处调用reactor.callLater()
)安排它,或执行更多复杂的计算来确定何时开始,跟踪已用时间。
当您在Twisted等待中没有意识到任何事情时,处理完成所有计划任务时关闭连接变得非常简单:您只需将最后一个任务调用self.transport.loseConnection()
即可。对于更复杂的情况,您可能希望将Deferred
连锁在一起,或者在所有未完成任务完成时使用DeferredList
执行loseConnection()
,即使它们并非严格按顺序执行。
这笔交易的最终解决方案..
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)
Just fyi:'self.scenario .__ iter __()' - >'iter(self.scenario)','self.sc.next()' - >'next(self.sc)'(从2.6开始) – 2010-07-23 13:15:10
谢谢,改了。 – DominiCane 2010-07-25 12:28:40
谢谢,现在我明白了为什么“睡大觉”,没有工作。你能举一个例子,在前面reactor.callLater()的末尾安排reactor.callLater()吗? – DominiCane 2010-07-22 05:12:40
只需定义一个调用'self.sendata(data)'的函数,然后为下一个回调调用'reactor.callLater()',并将该函数传递给第一个'reactor.callLater()'而不是'self.sendata ' – 2010-07-22 18:26:53