Analysis of Reactor Thread Model

Reactor mode is a relatively common mode for processing concurrent I/O. It is used for synchronous I/O. The central idea is to register all the I/O events to be processed on a central I/O multiplexer. The thread is blocked on the multiplexer; once an I/O event arrives or is ready (the difference is whether the multiplexer is edge-triggered or level-triggered), the multiplexer returns and the corresponding I/O event Distributed to the corresponding processor.

Reactor is an event-driven mechanism. The difference from ordinary function calls is that the application does not actively call an API to complete the processing, but on the contrary, Reactor reverses the event processing flow, and the application needs to provide the corresponding interface And register to Reactor, if the corresponding event occurs, Reactor will actively call the interface registered by the application, these interfaces are also called "callback functions." "Hollywood Principles" can not be more appropriate to describe Reactor: Don't call us, we will call you to inform you.

Reactor mode is very similar to Observer mode in some respects: when a subject changes, all dependent entities are notified. However, the observer mode is associated with a single event source, while the reactor mode is associated with multiple event sources.

Reactor structure

Insert picture description here
The figure above is the Reactor model, the main classes involved:

Initiation Dispatcher: EventHandler container, used to register, remove EventHandler, etc.; in addition, it is used as the entrance of Reactor mode to call the select method of Synchronous Event Demultiplexer to block the return of waiting for the event. When the blocking event returns, the Handle of the event is distributed To the corresponding EvenHandler for processing.
Even Handler: defines the method of event processing.
Handle: The handle in the operating system is an abstraction of resources at the operating system level. It can be an open file, a connection (Socket), a Timer, etc.
Synchronous Event Demultiplexer: Use an event loop to block all resources. When it is possible to start a synchronization operation on the resources without blocking, the demultiplexer sends the resources to the distributor.

Reactor timing diagram

Insert picture description here

  • Initialize InvitationDispatcher, and initialize a Map of Handle to EventHandler.
  • Register EvenHandler to InvitationDispatcher, each EventHandler contains
    a reference to the corresponding Handle , thereby establishing a Handle to EventHandler mapping (Map).
  • Call the handle_events() method of the InitiationDispatcher to start the Event Loop. In the Event
    Loop, call the select() method (Synchronous Event Demultiplexer) to block waiting for the Event to occur.
  • When a certain Handle event occurs, the select() method returns, and the InitiationDispatcher
    finds the registered EventHandler according to the returned Handle, and calls back the handle_events()
    method of the EventHandler .
  • In the handle_events() method of EventHandler, you can also register a new
    Eventhandler to the InitiationDispatcher . For example, for AcceptorEventHandler, when a new client connects, it will generate a new EventHandler to handle the new connection and register it in the InitiationDispatcher.

Insert picture description here

[Article benefits] The editor recommends my own Linux and C/C++ technical exchange group: [960994558] I have compiled some learning books and video materials that I think are better for sharing (including C/C++, Linux, Nginx, ZeroMQ, MySQL) , Redis, fastdfs, MongoDB, ZK, streaming media, CDN, P2P, K8S, Docker, TCP/IP, coroutine, DPDK, etc.), you can add it yourself if you need it! ~

Pattern model

Single thread model

This is the simplest single-Reactor single-threaded model. The Reactor thread is a generalist, responsible for demultiplexing sockets, accepting new connections, and dispatching requests to the processor chain. This model is suitable for scenarios where business processing components in the processor chain can be completed quickly. However, this single-threaded model cannot make full use of multi-core resources, so it is not actually used much.
Insert picture description here

Multi-threaded model (single Reactor)

Compared with the previous model, this model uses multithreading (thread pool) in the Handler chain, which is also a commonly used model for back-end programs.
Insert picture description here

Multi-threaded model (multi-reactor)

Compared with the second model, this model divides the Reactor into two parts. The mainReactor is responsible for monitoring and accepting new connections, and then the established socket is assigned to the subReactor through a multiplexer (Acceptor). subReactor is responsible for multiplexing the connected sockets, reading and writing network data; business processing functions, which are handed over to the worker thread pool to complete. Generally, the number of subReactors can be equal to the number of CPUs.
Insert picture description here

Pros and cons of Reactor

advantage:

The commonalities of most design patterns: decoupling, improving reusability, modularity, portability, event-driven, fine-grained concurrency control, etc.
More significant is the performance improvement, that is, there is no need for each client to correspond to a thread, which reduces the use of threads.

Disadvantages:

Compared with the traditional simple model, Reactor adds a certain degree of complexity, so it has a certain threshold and is not easy to debug.
The Reactor mode requires the support of the underlying Synchronous Event Demultiplexer, such as the Selector support in Java and the select system call support of the operating system. If you want to implement the Synchronous Event Demultiplexer yourself, it may not be so efficient.
The Reactor mode is implemented in the same thread when IO reads and writes data. Even if multiple Reactor mechanisms are used, if there is a long time reading and writing of data in those Channels that share a Reactor, it will affect other Channels in this Reactor. For example, when transferring large files, the IO operation will affect the corresponding time of other clients. Therefore, for this operation, using traditional Thread-Per-Connection may be a better choice, or use Proactor at this time mode.

Guess you like

Origin blog.csdn.net/weixin_52622200/article/details/110821355