简体   繁体   English

Python的Twisted Reactor如何工作?

[英]How does Python's Twisted Reactor work?

Recently, I've been diving into the Twisted docs. 最近,我一直在深入研究Twisted文档。 From what I gathered, the basis of Twisted's functionality is the result of it's event loop called the "Reactor". 从我收集的内容来看,Twisted功能的基础是它的事件循环称为“Reactor”。 The reactor listens for certain events and dispatches them to registered callback functions that have been designed to handle these events. reactor侦听某些事件并将它们分派给已设计用于处理这些事件的已注册回调函数。 In the book, there is some pseudo code describing what the Reactor does but I'm having trouble understanding it, it just doesn't make any sense to me. 在书中,有一些伪代码描述了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()

What does this mean? 这是什么意思?

In case it's not obvious, It's called the reactor because it reacts to things . 如果它不明显,它被称为反应堆,因为它对事物作出反应 The loop is how it reacts. 循环是如何反应。

One line at a time: 一次一行:

while True:

It's not actually while True ; 实际上不是while True ; it's more like while not loop.stopped . 它更像是while not loop.stopped You can call reactor.stop() to stop the loop, and (after performing some shut-down logic) the loop will in fact exit. 你可以调用reactor.stop()来停止循环,并且(在执行一些关闭逻辑之后)循环实际上会退出。 But it is portrayed in the example as while True because when you're writing a long-lived program (as you often are with Twisted) it's best to assume that your program will either crash or run forever, and that "cleanly exiting" is not really an option. 但是在示例中描述的是while True因为当你编写一个长期存在的程序时(就像你经常使用Twisted一样),最好假设你的程序要么崩溃要么永远运行,而且“干净地退出”是不是一个选择。

     timeout = time_until_next_timed_event()

If we were to expand this calculation a bit, it might make more sense: 如果我们稍微扩展一下这个计算,可能会更有意义:

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 is the list of events scheduled with reactor.callLater ; timed_events是预定的事件列表reactor.callLater ; ie the functions that the application has asked for Twisted to run at a particular time. 即应用程序要求Twisted在特定时间运行的函数。

     events = wait_for_events(timeout)

This line here is the "magic" part of Twisted. 这一行是Twisted的“神奇”部分。 I can't expand wait_for_events in a general way, because its implementation depends on exactly how the operating system makes the desired events available. 我无法以一般方式扩展wait_for_events ,因为它的实现取决于操作系统如何使所需事件可用。 And, given that operating systems are complex and tricky beasts, I can't expand on it in a specific way while keeping it simple enough for an answer to your question. 而且,鉴于操作系统是复杂而棘手的野兽,我不能以特定的方式扩展它,同时保持它足够简单以回答你的问题。

What this function is intended to mean is, ask the operating system, or a Python wrapper around it, to block, until one or more of the objects previously registered with it - at a minimum, stuff like listening ports and established connections, but also possibly things like buttons that might get clicked on - is "ready for work". 这个函数的意思是,要求操作系统或它周围的Python包装器阻塞,直到之前注册的一个或多个对象 - 至少是监听端口和已建立的连接等东西,还要可能点击的按钮可能是“准备工作”。 The work might be reading some bytes out of a socket when they arrive from the network. 当工作从网络到达时,工作可能是从套接字中读取一些字节。 The work might be writing bytes to the network when a buffer empties out sufficiently to do so. 当缓冲区足够清空时,工作可能是将字节写入网络。 It might be accepting a new connection or disposing of a closed one. 它可能正在接受新连接或处理已关闭的连接。 Each of these possible events are functions that the reactor might call on your objects: dataReceived , buildProtocol , resumeProducing , etc, that you will learn about if you go through the full Twisted tutorial. 这些可能的事件中的每一个都是reactor可能在您的对象上调用的函数: dataReceivedbuildProtocolresumeProducing等,如果您完成完整的Twisted教程,您将了解这些函数。

Once we've got our list of hypothetical "event" objects, each of which has an imaginary " process " method (the exact names of the methods are different in the reactor just due to accidents of history), we then go back to dealing with time: 一旦我们得到了假设的“事件”对象列表,每个对象都有一个假想的“ process ”方法(由于历史事故,反应堆的确切名称在反应堆中是不同的),然后我们回到处理随着时间的推移:

     events += timed_events_until(now())

First, this is assuming events is simply a list of an abstract Event class, which has a process method that each specific type of event needs to fill out. 首先,假设events只是一个抽象Event类的list ,它有一个每个特定类型事件需要填写的process方法。

At this point, the loop has "woken up", because wait_for_events , stopped blocking. 此时,循环已“唤醒”,因为wait_for_events停止了阻塞。 However, we don't know how many timed events we might need to execute based on how long it was "asleep" for . 但是,我们不知道根据“睡着多长时间”我们可能需要执行多少个定时事件。 We might have slept for the full timeout if nothign was going on, but if lots of connections were active we might have slept for effectively no time at all. 如果nothign正在进行,我们可能已经睡了整个超时,但如果有很多连接处于活动状态,我们可能根本没有时间睡觉。 So we check the current time (" now() "), and we add to the list of events we need to process, every timed event with a desired_time that is at, or before, the present time. 所以我们检查当前时间(“ now() ”),然后我们添加到我们需要处理的事件列表中,每个定时事件都有一个在当前时间或之前的desired_time

Finally, 最后,

     for event in events:
         event.process()

This just means that Twisted goes through the list of things that it has to do and does them. 这只是意味着Twisted会完成它必须做的事情列表并完成它们。 In reality of course it handles exceptions around each event, and the concrete implementation of the reactor often just calls straight into an event handler rather than creating an Event -like object to record the work that needs to be done first, but conceptually this is just what happens. 实际上它当然会处理每个事件的异常,而反应器的具体实现通常直接调用事件处理程序,而不是创建一个类似Event的对象来记录需要先完成的工作,但从概念上讲,这只是怎么了。 event.process here might mean calling socket.recv() and then yourProtocol.dataReceived with the result, for example. event.process这里可能意味着调用socket.recv()然后yourProtocol.dataReceived与结果,例如。

I hope this expanded explanation helps you get your head around it. 我希望这个扩展的解释可以帮助您了解它。 If you'd like to learn more about Twisted by working on it, I'd encourage you to join the mailing list , hop on to the IRC channel, #twisted to talk about applications or #twisted-dev to work on Twisted itself, both on Freenode . 如果您想通过它的工作更多地了解扭曲,我会鼓励你加入邮件列表 ,跳到IRC频道, #twisted谈谈应用程序或#twisted-dev对双绞线本身的工作,都在Freenode

I will try to elaborate: 我会试着详细说明:

  • The program yields control and go to sleep on wait for events. 该程序产生控制并在等待事件时进入休眠状态。 I suppose the most interesting part here is event. 我想这里最有趣的部分是事件。 Event is: on external demand (receiving network packet, click on a keyboard, timer, different program call) the program receives control (in some other thread or in special routine). 事件是:在外部需求(接收网络数据包,点击键盘,定时器,不同程序调用)程序接收控制(在某些其他线程或特殊例程中)。 Somehow the sleep in wait_for_events becomes interrupted and wait_for_events returns. 不知怎的, wait_for_events中的sleep会中断并且wait_for_events返回。

  • On that occurrence of control the event handler stores information of that event into some data structure, events , which later is used for doing something about that events ( event->process ). 在发生控制时,事件处理程序将该事件的信息存储到某些数据结构事件中事件稍后用于执行有关该事件的事件事件 - >进程 )。 There can happen not only one, but many events in the time between entering and exiting of wait_for_events , all of them must be processed. 在进入和退出wait_for_events之间不仅会发生一次,而且会发生很多事件,所有事件都必须进行处理。 The event->process () procedure is custom and should usually call the interesting part - user's twisted code. event-> process ()过程是自定义的,通常应该调用有趣的部分 - 用户的扭曲代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM