Article Source: http://www.zhixing123.cn/jsp/reactor.html
Typically, the file or device specified for a file descriptor has two ways of working: blocking and non-blocking. The so-called blocking means that when attempting to read and write the file descriptor, if there is nothing to read, or temporarily not writable, the program enters the waiting state until something is readable or writable. For non-blocking states, if nothing is readable or not writable, the read-write function returns immediately without waiting.
In the example of TCP communication mentioned in the previous section, the blocking mode is used: When receiving TCP data, if there is no data to read at the far end, it will be blocked until the required data is read. This mode of transmission is similar to the traditional passive method of invocation, very intuitive, and simple and effective, but there is also an efficiency problem, if you are developing a server program facing thousands of connections, for each client is blocking the way to communicate, if there is a very time-consuming read and write operations, Other client communications will be unresponsive and inefficient.
A common practice is to create a new thread to communicate with each socket separately (in a blocking manner), each time a socket connection is established. This approach has a high response speed, and control is very simple, when the number of connections is very effective, but if each connection to produce a thread is undoubtedly a waste of system resources, if the number of connections will be insufficient resources.
Another more efficient approach is to save a list of sockets on the server side, then poll the list, and if you find data readable on a socket port (read-ready), call the corresponding read operation of the socket connection If a socket port is found to have data writable (write-ready), the corresponding write operation for that socket is invoked, and if a port's socket connection is interrupted, the appropriate destructor is called to close the port. This can make full use of server resources, the efficiency has been greatly improved.
System I/O can be divided into blocking, non-blocking synchronous and non-blocking asynchronous three classes, in three ways, non-blocking asynchronous mode of scalability and performance best. This paper mainly introduces two kinds of IO multiplexing modes: Reactor and Proactor, and compares them. actor
Two IO multiplexing modes: Reactor and Proactor
Generally, the I/O multiplexing mechanism relies on an event demultiplexer. The Separator object separates the I/O events from the event source and distributes them to the corresponding Read/write event handler (the event Handler). The developer pre-registers the events and their event handlers (or callback functions) that need to be processed, and the event separator is responsible for passing the request events to the event handler. The two patterns associated with event separators are reactor and proactor. the reactor mode uses synchronous IO, while the proactor uses asynchronous IO.
In reactor, the event splitter is responsible for waiting for the file descriptor or socket to be ready for read and write operations, then passing the ready event to the corresponding processor, and finally the processor is responsible for completing the actual read and write work.
In Proactor mode, the processor – or the event splitter that is the processor, is only responsible for initiating asynchronous read and write operations. The IO operation itself is done by the operating system. The parameters passed to the operating system need to include the user-defined data buffer address and data size, from which the operating system can get the data it needs to write the operation, or write the data read from the socket. The event splitter captures the IO operation completion event and then passes the event to the corresponding processor. For example, on Windows, the processor initiates an asynchronous IO operation, and the event splitter waits for the IoCompletion event. Typical asynchronous Pattern implementations are built on the operating system's support for asynchronous APIs, which we call "system-level" asynchronous or "true" asynchrony because the application relies entirely on the operating system to perform real IO work.
For example, it will help to understand the difference between reactor and Proactor, as in the case of a read operation (similar to a class operation).
Read in the reactor
Registering read-Ready events and corresponding event handlers
Event separator waits for an event (synchronous wait, selects the Ready IO port via Select (), executes the thread)
Event arrives, activates the splitter, and the splitter invokes the event corresponding to the processor.
The event handler completes the actual read operation, processes the read data, registers the new event, and then returns control.
Read in the Proactor
The processor initiates an asynchronous read operation (note: The operating system must support asynchronous IO). In this case, the processor ignores the IO-ready event, and it focuses on the completion event.
Event Splitter waits for Operation completion event
During the separator wait, the operating system takes advantage of the parallel kernel thread to perform the actual read operation and stores the result data in the user-defined buffer, and finally notifies the event splitter that the read operation is complete.
Event Splitter Calling processor
The event handler handles the data in the user-defined buffer, then initiates a new asynchronous operation and returns control to the event splitter.
Java NiO non-clogging applications are commonly used in I/O reading and writing, we know that the performance bottleneck of the system operation is usually in the I/O read and write, including port and file operation, in the past, after opening an I/O channel, read () will be waiting on the port side read the byte content, if no content comes in, Read () is also silly and so on, this will affect our program to continue to do other things, then the improvement is to open a thread, let the thread to wait, but this is also very resource-intensive.
Java NiO Non-clogging technology is actually to take the reactor mode , or observer mode for us to monitor the I/O port, if the content comes in, will automatically notify us, so that we do not have to open multiple threads death, from the outside, to achieve a smooth I/O Read and write , not clogged up.
Java NiO appears not just a technical performance improvement, you'll find it everywhere on the web, because it's a milestone, Starting with JDK1.4, Java has started to improve performance-related features, allowing Java to be kept abreast of languages such as C or Perl in the underlying or parallel distributed computing operations.
The main principle and application of NIO.
NIO has a major class selector, which resembles an observer, so long as we tell selector what we need to know, we go on to do something else, and when something happens, he informs us, returns a group of Selectionkey, We read these keys, we get the socketchannel we just registered, and then we read the data from the channel, and we can read the packet, and then we could process the data.
Selector internal principle is actually doing a polling access to the registered channel, constantly polling (currently this algorithm), once polling to a channel to register things happen, such as the data came, he will stand up report, hand over a key, Let's use this key to read the channel's contents.
Reactor (Reactor) architecture pattern for event Multiplexing and dispatch