Python扭曲:如何调度?
在 Twisted 中有 1 天的经验,我尝试安排消息发送以回复 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)
现在它发送消息,但我有 2 个问题:
1)“超时”是从“现在”开始的,我想在之前的每个任务完成后(发送之前的消息)进行计数
2)我不知道如何在发送所有消息后关闭连接。如果我将 self.transport.loseConnection()
放在 callLater
之后,它会立即关闭连接。
在之前的尝试中,我没有使用 reactor.callLater
,而只使用 self.transport.write()
和 time.sleep(n)
for
循环。在这种情况下,所有消息都在所有超时过去后一起发送...这不是我想要的。
目的是等待客户端连接,等待超时1并发送消息1,等待超时2并发送消息2,...等。在最终消息之后 - 关闭连接。
Having 1-day experience in Twisted I try to schedule message sending in reply to tcp client:
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)
Now it sends messages, but I have 2 problems:
1) "timeout" is going from "now", and I want to count it after each previous task was completed (previous message was sent)
2) I don't know how to close connection after all messages were sent. If I place self.transport.loseConnection()
after callLater
s it closes connection immediately.
In previous try I didn't use reactor.callLater
, but only self.transport.write()
and time.sleep(n)
in for
loop. In this case all messages were sent together after all timeouts passed... Not something I wanted.
The purpose is to wait for client connection, wait timeout1 and send message1, wait timeout2 and send message2, ... etc. After final message - close connection.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用 Twisted 时要认识到的重要一点是,没有什么会等待。当您调用reactor.callLater()时,您是在要求反应器稍后调用某些内容,而不是现在。调用立即完成(在安排调用之后,在执行调用之前)。因此,您的
print
语句是一个谎言:您没有等待超时
时间;你根本就没有等。您可以通过多种方式修复它,使用哪种方式取决于您的实际需要。如果您希望第二个任务在第一个任务启动后四秒启动,您只需将第一个任务的延迟(您的
超时
变量)添加到第二个任务的延迟中即可。第二个任务。不过,第一个任务可能不会在您安排的时间准确开始;如果 Twisted 太忙而无法早点开始,则可能会稍后开始。此外,如果您的任务需要很长时间,则在第二个任务开始之前实际上可能尚未完成。更常见的方式是第一个任务调度第二个任务,而不是立即调度第二个任务。您可以在第一个任务结束后四秒(通过在第一个任务结束时调用reactor.callLater())安排它,或者在第一个任务开始后四秒(通过调用reactor .callLater()(在第一个任务的开始处),或者执行更复杂的计算来确定它应该何时开始,并跟踪经过的时间。
当您意识到 Twisted 等待中没有任何内容时,在执行完所有计划任务后关闭连接的处理就变得很容易:您只需调用最后一个任务
self.transport.loseConnection()
即可。对于更复杂的情况,您可能需要将 Deferred 链接在一起,或者在所有待处理任务完成时使用 DeferredList 执行 loseConnection() ,即使它们不是严格顺序的。The important thing to realize when working with Twisted is that nothing waits for anything. When you call
reactor.callLater()
, you're asking the reactor to call something later, not now. The call finishes right away (after the call has been scheduled, before it has been executed.) Consequently, yourprint
statement is a lie: you didn't waittimeout
time; you didn't wait at all.You can fix it in multiple ways, and which to use depends on what you actually want. If you want the second task to start four seconds after the first task started, you can simply add the delay (your
timeout
variable) of the first task to the delay of the second task. The first task may not start exactly when you schedule it, though; it may start later, if Twisted is too busy to start it sooner. Also, if your task takes a long time it may not actually be done before the second task starts.The more common way is for the first task to schedule the second task, instead of scheduling the second task right away. You can schedule it four seconds after the first task ended (by calling
reactor.callLater()
at the end of the first task), or four seconds after the first task started (by callingreactor.callLater()
at the start of the first task), or perform more complex calculations to determine when it should start, keeping track of elapsed time.When you realize nothing in Twisted waits, dealing with closing the connection when you've performed all scheduled tasks becomes easy: you simply have your last task call
self.transport.loseConnection()
. For more complex situations you may want to chainDeferred
s together, or use aDeferredList
to perform theloseConnection()
when all pending tasks have finished, even when they aren't strictly sequential.这笔交易的最终解决方案..
Final solution for this deal..