What is the difference between event driven model and reactor pattern? [closed]

守給你的承諾、 提交于 2019-11-28 02:32:39

The reactor pattern is more specific than "event driven programming". It is a specific implementation technique used when doing event driven programming. However, the term is not used with much accuracy in typical conversation, so you should be careful about using it and expecting your audience to understand you, and you should be careful in how you interpret the term when you encounter its use.

One way to look at the reactor pattern is to consider it closely related to the idea of "non-blocking" operations. The reactor sends out notifications when certain operations can be completed without blocking. For example, select(2) can be used to implement the reactor pattern for reading from and writing to sockets using the standard BSD socket APIs (recv(2), send(2), etc). select will tell you when you can receive bytes from a socket instantly - because the bytes are present in the kernel receiver buffer for that socket, for example.

Another pattern you might want to consider while thinking about these ideas is the proactor pattern. In contrast to the reactor pattern, the proactor pattern has operations start regardless of whether they can finish immediately or not, has them performed asynchronously, and then arranges to deliver notification about their completion.

The Windows I/O Completion Ports (IOCP) API is one example where the proactor pattern can be seen. When performing a send on a socket with IOCP, the send operation is started regardless of whether there is any room in the kernel send buffer for that socket. The send operation continues (in another thread, perhaps a thread in the kernel) while the WSASend call completes immediately. When the send actually completes (meaning only that the bytes being sent have been copied into the kernel send buffer for that socket), a callback function supplied to the WSASend call is invoked (in a new thread in the application).

This approach of starting operations and then being notified when they are complete is central to the idea of asynchronous operations. Compare it to non-blocking operations where you wait until an operation can complete immediately before attempting to perform it.

Either approach can be used for event driven programming. Using the reactor pattern, a program waits for the event of (for example) a socket being readable and then reads from it. Using the proactor pattern, the program instead waits for the event of a socket read completing.

Strictly speaking, Twisted misuses the term reactor. The Twisted reactor which is based on select(2) (twisted.internet.selectreactor) is implemented using non-blocking I/O, which is very reactor-like. However, the interface it exposes to application code is asynchronous, making it more proactor-like. Twisted also has a reactor based on IOCP. This reactor exposes the same asynchronous application-facing API and uses the proactor-like IOCP APIs. This hybrid approach, varying from platform to platform in its details, makes neither the term "reactor" nor "proactor" particularly accurate, but since the API exposed by twisted.internet.reactor is basically entirely asynchronous instead of non-blocking, proactor would probably have been a better choice of name.

I think that this separation "non-blocking" and "asynchronous" is wrong, as the main implication of "asynchronous" is "non-blocking". Reactor pattern is about asynchronous (so non-blocking) calls, but synchronous (blocking) processing of those calls. Proactor is about asynchronous (non-blocking) calls and asynchronous (non-blocking) processing of those calls.

To handle TCP connections, there are two competing web architectures, namely thread-based architecture and event-driven architecture.

Thread-Based Architecture

The oldest way of implementing a multi-threaded server is following the “thread per connection” approach. In order to control and limit the number of running threads, a single dispatcher thread can be used along with a bounded blocking queue and a thread pool.

The dispatcher blocks on a TCP socket for new connections and offers them to the bounded blocking queue. TCP connections exceeding the bound of the queue will be dropped allowing the accepted connections to operate with a desirable and predictable latency.

Event-Driven Architecture

Separating threads from connections, event-driven architecture only allows threads to be used for events on specific handlers.

This creative concept allows Reactor Pattern to come out of the shelf and show off. A system built on this architecture consists of event creators and event consumers.

The Reactor Pattern

The reactor pattern is the most popular implementation technique of event-driven architecture for TCP connection handling. In simple terms, it uses a single-threaded event loop, blocking on events and dispatches those events to corresponding handlers.

There is no need for other threads to block on I/O, as long as handlers for events are registered to take care of them. Considering a TCP connection, we can easily refer events to these instances: connected, input-ready, output-ready, timeout, and disconnected.

Reactor pattern decouples the modular application-level code from reusable reactor implementation. To achieve that, the architecture of the reactor pattern consists of two important participants — Reactor and Handlers.

Reactor

A Reactor runs in a separate thread, and it is reacting to the I/O events such as connected, input-ready, output-ready, timeout and disconnected, by dispatching the work to the appropriate registered handler.

Handlers

A Handler performs the actual work or the response that needs to be done with an I/O event. A Reactor responds to I/O events by dispatching the appropriate handler.

“Pattern Languages of Program Design” by Jim Coplien and Douglas C. Schmidt which was published way back in 1995, is one of the books that has explained the Reactor Pattern in detail.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!