【问题标题】:Python twisted: how to schedule?Python 扭曲:如何调度?
【发布时间】:2011-03-19 03:32:31
【问题描述】:

在 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) 发送完所有消息后,我不知道如何关闭连接。如果我在callLaters 之后放置self.transport.loseConnection(),它会立即关闭连接。

在之前的尝试中,我没有使用reactor.callLater,而在for 循环中只使用了self.transport.write()time.sleep(n)。在这种情况下,所有消息都在所有超时过后一起发送......这不是我想要的。
目的是等待客户端连接,等待timeout1并发送message1,等待timeout2并发送message2,...等最终消息后-关闭连接。

【问题讨论】:

    标签: python networking twisted


    【解决方案1】:

    在使用 Twisted 时要意识到的重要一点是,什么都不等待。当您调用reactor.callLater() 时,您是在要求反应器稍后调用某些东西,而不是现在。调用立即结束(在调用被安排之后,它已经被执行。)因此,你的print 声明是一个谎言:你没有等待timeout 时间;你根本没有等。

    您可以通过多种方式修复它,使用哪种方式取决于您的实际需求。如果您希望第二个任务在第一个任务开始后四秒开始,您可以简单地将第一个任务的延迟(您的timeout 变量)添加到第二个任务的延迟。但是,第一个任务可能不会在您安排它时准确地开始;如果 Twisted 太忙而不能早点启动,它可能会晚一点启动。此外,如果您的任务需要很长时间,则可能在第二个任务开始之前实际上并未完成。

    更常见的方法是让第一个任务调度第二个任务,而不是立即调度第二个任务。您可以在第一个任务结束后四秒(通过在第一个任务结束时调用reactor.callLater())或在第一个任务开始后四秒(通过在开始处调用reactor.callLater()的第一个任务),或者执行更复杂的计算以确定它应该何时开始,并跟踪经过的时间。

    当您在 Twisted 等待中什么都没有意识到时,在您执行所有计划任务后关闭连接变得容易:您只需将最后一个任务调用 self.transport.loseConnection()。对于更复杂的情况,您可能希望将Deferreds 链接在一起,或者使用DeferredList 在所有待处理任务完成后执行loseConnection(),即使它们不是严格按顺序执行的。

    【讨论】:

    • 谢谢,现在我明白为什么“睡眠”不起作用了。你能举个例子,在前面的 reactor.callLater() 结束时调度 reactor.callLater() 吗?
    • 只需定义一个调用self.sendata(data)的函数,然后为下一个回调调用reactor.callLater(),并将该函数传递给第一个reactor.callLater()而不是self.sendata
    【解决方案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)
    

    【讨论】:

    • 仅供参考:self.scenario.__iter__() -> iter(self.scenario), self.sc.next() -> next(self.sc)(我认为是从 2.6 开始)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-05
    • 2014-09-18
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多