Reactor pattern in Tornado

前言: 在看 tornado v1.0 的服務(wù)器部分的源碼時(shí),當(dāng)時(shí)傻乎乎的還不懂啥是 reactor 設(shè)計(jì)模式,看得真心是頭痛!那時(shí),只知道一個(gè)叫 單例模式的。看來,軟件的設(shè)計(jì)架構(gòu)還是真心有用的。(這是個(gè)套路...)

接下來就簡單的分析一下 tornado 中的 reactor pattern, 由于才疏學(xué)淺,難免有錯(cuò),還請(qǐng)指教!
預(yù)備知識(shí):知道 socket, epoll 的原理及使用,當(dāng)然,最好也是看了 tornado 中的服務(wù)器部分的源碼以及這篇 Reactor: An Object Behavioral Pattern for
Demultiplexing and Dispatching Handles for Synchronous Events

What's Reactor

來自 wikipedia 的簡明版:

The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.

一個(gè) Reactor 中通常有幾個(gè)元素:

  • Resources
    Any resource that can provide input to or consume output from the system.

  • Synchronous Event Demultiplexer
    Uses an event loop to block on all resources. The demultiplexer sends the resource to the dispatcher when it is possible to start a synchronous operation on a resource without blocking (Example: a synchronous call to read() will block if there is no data to read. The demultiplexer uses select() on the resource, which blocks until the resource is available for reading. In this case, a synchronous call to read() won't block, and the demultiplexer can send the resource to the dispatcher.)

  • Dispatcher
    Handles registering and unregistering of request handlers. Dispatches resources from the demultiplexer to the associated request handler.

  • Request Handler
    An application defined request handler and its associated resource.

來自這篇 Reactor 文章的詳細(xì)版

The Reactor design pattern handles service requests that are
delivered concurrently to an application by one or more
clients. Each service in an application may consist of
serveral methods and is represented by a separate event handler
that is responsible for dispatching service-specific requests.
Dispatching of event handlers is performed by an initiation
dispatcher, which manages the registered event handlers.
Demultiplexing of service requests is performed by a
synchronous event demultiplexer.

  • Handles
    Identify resources that are managed by an OS. These resources commonly include network connections, open files, timers, synchronization objects, etc.

  • Synchronous Event Demultiplexer
    Blocks awaiting events to occur on a set of Handles. It returns when it is possible to initiate an operation on a Handle without blocking. A common demultiplexer for I/O events is select, which is an event demultiplexing system call provided by the UNIX and Win32 OS platforms. The select call indicates which Handles can have operations invoked on them synchronously without blocking the application process.

  • Initiation Dispatcher
    Defines an interface for registering, removing, and dispatching Event Handlers. Ultimately, the Synchronous Event Demultiplexer is responsible for waiting until new events occur. When it detects new events, it informs the Initiation Dispatcher to call back application-specific event handlers. Common events include connection acceptance events, data input and output events, and timeout events.

  • Event Handler
    Specifies an interface consisting of a hook method that abstractly represents the dispatching operation for service-specific events. This method must be implemented by application-specific services.

  • Concrete Event Handler
    Implements the hook method, as well as the methods to process these events in an application-specific manner. Applications register Concrete Event Handlers with the Initiation Dispatcher to process certain types of events. When these events arrive, the Initiation Dispatcher calls back the hook method of the appropriate Concrete Event Handler.

reactor_structure

Reactor structure in Tornado

由上面對(duì) reactor structure 的理解,進(jìn)一步推理到 Tornado 中:

  • handle 或是 resource 就是指一個(gè)網(wǎng)絡(luò)連接 socket;

  • 一個(gè) event 就是這個(gè) socket 監(jiān)聽的類型, 比如 read or write etc;

  • handler, 在tornado 中就是一個(gè) RequestHandler class. 上面的 Event Handler 對(duì)應(yīng) tornado 中 RequestHandler 基類,而 Concrete Event Handler 對(duì)應(yīng) tornado 中用戶自定義的繼承 RequestHandler 的類, 如下:

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
  • Synchronous Event Demultiplexer (或者稱它為 Notifier) 就如同 epoll 或者 select, 用于監(jiān)聽注冊(cè)了特定 event 事件的 handle.

  • Initiation Dispatcher 就是 tornado 中的 IOLoop.

General Collaborations

各模塊之間的協(xié)作,如下圖所示.

reactor_work

請(qǐng)注意上圖最左邊縱向的字為: INITIALIZATION MODE, EVENT HANDLING MODE. 這意味著可以將這個(gè)模式的工作方式分解成這2個(gè)小模塊來分析.

Initialization Mode

  • 1 When an application registers a Concrete Event Handler with the Initiation Dispatcher the application indicates the type of event(s) this Event Handler wants the Initiation Dispatcher to notify it about when the event(s) occur on the associated Handle.

  • 2 The Initiation Dispatcher requests each Event Handler to pass back its internal Handle. This Handle identifies the Event Handler to the
    OS.

  • 3 After all Event Handlers are registered, an application calls handle events to start the Initiation Dispatcher’s event loop. At this point, the Initiation Dispatcher combines the Handle from each registered Event Handler and uses the Synchronous Event Demultiplexer to wait for events to occur on these Handles. For instance, the TCP protocol layer uses the select synchronous event demultiplexing operation to wait for client logging record events to arrive on connected socket Handles.

Event Handling Mode

  • 1 The Synchronous Event Demultiplexer notifies the Initiation Dispatcher when a Handle corresponding to an event source becomes “ready,” e.g., that a TCP socket is “ready for reading.”

  • 2 The Initiation Dispatcher triggers Event Handler hook method in response to events on the ready Handles. When events occur, the Initiation Dispatcher uses the Handles activated by the event sources as “keys” to locate and dispatch the appropriate Event Handler’s hook method.

  • 3 The Initiation Dispatcher calls back to the handle event hook method of the Event Handler to perform application-specific functionality in response to an event. The type of event that occurred can be passed as a parameter to the method and used internally by this method to perform additional service specific demultiplexing and dispatching.

Initialization Mode in Tornado

  • 1 在 Application 類中,生成 url 映射, 一個(gè)url對(duì)應(yīng)一個(gè)XXXRequestHandler處理方法; 在服務(wù)端中,創(chuàng)建了socket對(duì)象, 單例模式創(chuàng)建IOLoop對(duì)象,然后將socket對(duì)象句柄作為key,被封裝了的函數(shù)_handle_events作為value,添加到IOLoop對(duì)象的_handlers字段中(向Initiation Dispatcher 中注冊(cè) Handlers, 建議 socket fd 到 handler 的映射)

  • 2 向epoll中注冊(cè)監(jiān)聽服務(wù)端socket對(duì)象的讀可用事件(向 Synchronous Event Demultiplexer 中注冊(cè) handle 監(jiān)聽的 event 類型)

如下為 tornado v1.0.0 代碼

class IOLoop(object):
    ...
    def add_handler(self, fd, handler, events):
        """Registers the given handler to receive the given events for fd."""
        self._handlers[fd] = handler
        self._impl.register(fd, events | self.ERROR)
  • 3 開始IOLoop 調(diào)用 start() 函數(shù)開始Event Loop, epoll 開始監(jiān)聽注冊(cè)了的事件(對(duì)應(yīng)Initiation Dispatcher 調(diào)用 handle_events() );
class IOLoop(object):
    ...
    def start(self):
        """Starts the I/O loop.
        The loop will run until one of the I/O handlers calls stop(), which
        will make the loop stop after the current event iteration completes.
        """
        ...
        while True:
            # Never use an infinite timeout here - it can stall epoll
            poll_timeout = 0.2
            ...
            event_pairs = self._impl.poll(poll_timeout)
            ...
            self._events.update(event_pairs)
            while self._events:
                fd, events = self._events.popitem()
                ...
                    self._handlers[fd](fd, events)
                ...

Event Handling Mode in Tornado

  • 1 當(dāng) epoll 監(jiān)聽到一個(gè)或多個(gè)事件到來時(shí),將其放到 event_pairs 中(如上面代碼所示, Synchronous Event Demultiplexer通知Initiation Dispatcher handle 的到來 );

  • 2,3 根據(jù)handle 即 socket fd, IOLoop 找到并調(diào)用注冊(cè)了的 XXXRequestHandler 中的hood method, 比如 get, post..給予響應(yīng),返回 response 給 client;

Others

Define the Event Handling Interface

對(duì)應(yīng) tornado 中 RequestHandler 類的接口實(shí)現(xiàn),有兩種方法: 一種是 A single-method interface, 另一種是 A multi-method interface; 而 Tornado 中 RequestHandler 采用的是后種即 A multi-method Interface 的設(shè)計(jì)方法,因?yàn)镠TTP/1.1 總共就8種方法: GET HEAD POST OPTIONS PUT DELETE TRACE CONNECT;

class RequestHandler(object):
   ...
   def head(self, *args, **kwargs):
       raise HTTPError(405)

   def get(self, *args, **kwargs):
       raise HTTPError(405)
   ...

Determine the Number of Initiation Dispatchers in an Application

"Many applications can be structured using just one instance of the Reactor pattern. In this case, the Initiation Dispatcher can be implemented as a Singleton".

而 Tornado 中的 IOLoop 就是采用 Singleton 模式的實(shí)現(xiàn);

Reference

See also

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是Reactor模式 要回答這個(gè)問題,首先當(dāng)然是求助Google或Wikipedia,其中Wikipedia上...
    wiseAaron閱讀 5,068評(píng)論 4 7
  • reactor Understanding Reactor Pattern with Java NIOreacto...
    礪豪閱讀 2,403評(píng)論 0 1
  • 收集,我們?cè)谏钪形覀冇泻芏嗍露际钦f了沒有做,可又在做別的事時(shí)又想起來了,這樣就把我們的注意力給分散了,使我們沒法...
    c32316c20a41閱讀 116評(píng)論 0 0
  • 非監(jiān)督學(xué)習(xí)問題: 主要使用 RBM,Autoencoders。 監(jiān)督學(xué)習(xí)問題: 例如文字處理,圖像識(shí)別,物體識(shí)別,...
    重新出發(fā)_砥礪前行閱讀 319評(píng)論 0 0
  • 受夠了這樣的生存。 小鬼生病有些時(shí)刻了,喉嚨發(fā)出嘶啞的聲音,眼睛上粘著的液體表示上火,我束無對(duì)策著急,以為它被掐著...
    宋小朝閱讀 123評(píng)論 0 0

友情鏈接更多精彩內(nèi)容