【问题标题】:How does Python's Twisted Reactor work?Python 的 Twisted Reactor 是如何工作的?
【发布时间】:2016-05-08 18:24:19
【问题描述】:

最近,我一直在研究 Twisted 文档。根据我的收集,Twisted 功能的基础是它的事件循环称为“反应器”的结果。反应器侦听某些事件并将它们分派给已注册的回调函数,这些回调函数旨在处理这些事件。在书中,有一些伪代码描述了 Reactor 的功能,但我无法理解它,它对我来说没有任何意义。

 while True:
     timeout = time_until_next_timed_event()
     events = wait_for_events(timeout)
     events += timed_events_until(now())
     for event in events:
         event.process()

这是什么意思?

【问题讨论】:

    标签: python twisted event-loop reactor


    【解决方案1】:

    在不明显的情况下,它被称为 反应器,因为它反应 东西。循环是如何它的反应。

    一次一行:

    while True:
    

    不是其实 while True;它更像while not loop.stopped。您可以调用reactor.stop() 来停止循环,并且(在执行一些关闭逻辑之后)循环实际上将退出。但它在示例中被描述为while True,因为当您编写一个长期存在的程序时(就像您经常使用 Twisted 一样),最好假设您的程序要么崩溃要么永远运行,并且“干净地退出”不是一个真正的选择。

         timeout = time_until_next_timed_event()
    

    如果我们稍微扩展一下这个计算,它可能更有意义:

    def time_until_next_timed_event():
        now = time.time()
        timed_events.sort(key=lambda event: event.desired_time)
        soonest_event = timed_events[0]
        return soonest_event.desired_time - now
    

    timed_events 是使用reactor.callLater 安排的事件列表;即应用程序要求 Twisted 在特定时间运行的功能。

         events = wait_for_events(timeout)
    

    这里的这一行是 Twisted 的“神奇”部分。我无法以一般方式扩展wait_for_events,因为它的实现完全取决于操作系统如何使所需事件可用。而且,鉴于操作系统是复杂而棘手的野兽,我无法以特定方式对其进行扩展,同时保持其足够简单以回答您的问题。

    这个函数的意思是,要求操作系统或它周围的 Python 包装器阻止,直到一个或多个先前向它注册的对象 - 至少,像侦听端口和建立的连接之类的东西,但也可能是诸如可能被点击的按钮之类的东西 - 是“准备工作”。当它们从网络到达时,这项工作可能正在从套接字中读取一些字节。当缓冲区足够清空以执行此操作时,该工作可能正在向网络写入字节。它可能正在接受新连接或处理已关闭的连接。这些可能的事件中的每一个都是反应器可能在您的对象上调用的函数:dataReceivedbuildProtocolresumeProducing 等,如果您阅读完整的 Twisted 教程,您将了解这些。

    一旦我们得到假设的“事件”对象列表,每个对象都有一个虚构的“process”方法(由于历史事故,反应堆中方法的确切名称不同),我们然后回去处理时间:

         events += timed_events_until(now())
    

    首先,这是假设events 只是抽象Event 类的list,它有一个process 方法,每种特定类型的事件都需要填写。

    此时,循环已经“唤醒”,因为wait_for_events 停止了阻塞。但是,根据“休眠”了多长时间,我们不知道我们可能需要执行多少个定时事件。如果没有发生任何事情,我们可能已经睡了完全超时,但是如果有很多连接处于活动状态,我们可能实际上根本没有睡。因此,我们检查当前时间(“now()”),并将每个定时事件添加到我们需要处理的事件列表中,并在当前时间或之前添加desired_time

    最后,

         for event in events:
             event.process()
    

    这只是意味着 Twisted 会遍历它必须做的事情列表并执行它们。实际上它当然会处理每个事件周围的异常,并且反应器的具体实现通常只是直接调用事件处理程序而不是创建一个类似Event 的对象来记录需要首先完成的工作,但从概念上讲就是发生了什么。例如,这里的event.process 可能意味着调用socket.recv(),然后调用yourProtocol.dataReceived

    我希望这个扩展的解释可以帮助您理解它。如果你想通过工作了解更多关于 Twisted 的信息,我鼓励你join the mailing list,跳到 IRC 频道,#twisted 讨论应用程序或#twisted-dev 工作在 Twisted 本身,两者在Freenode

    【讨论】:

      【解决方案2】:

      我会尽量详细说明:

      • 程序让出控制权并在等待事件时进入睡眠状态。 我想这里最有趣的部分是事件。 事件是: 根据外部需求(接收网络数据包,点击键盘,定时器,不同的程序调用)程序接收控制(在其他一些线程或 在特殊程序中)。不知何故,wait_for_events 中的睡眠被中断,wait_for_events 返回。

      • 在控制发生时,事件处理程序将该事件的信息存储到某个数据结构 events 中,该结构稍后用于处理该 events事件->过程)。 在wait_for_events进入和退出之间的时间里可能不仅发生一个事件,而且可能发生许多事件,它们都必须被处理。 event->process() 过程是自定义的,通常应该调用有趣的部分——用户的扭曲代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-01-22
        • 2020-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-09
        相关资源
        最近更新 更多