NIO Learning 3--Basic model: Multiplexing model

Source: Internet
Author: User

Reactor mode and NIO

This article can be seen as a translation of Doug Lea scalable IO in Java.

The current distributed computing Web services are prevalent in the world, the bottom of these network service is inseparable from the operation of the socket. They all have a common structure:
1. Read Request
2. Decode Request
3. Process Service
4. Encode reply
5. Send Reply

The classic Network service is designed for example, to complete the processing of the data in each thread:

However, such a pattern will degrade very quickly when the user load is added. We need to find a new solution to keep the data flowing smoothly, and it is clear that the event triggering mechanism is the best solution, and when something happens, it touches the handler and starts the processing of the data.

Reactor mode is similar to event handling in AWT:

Reactor Model participant

1.Reactor is responsible for responding to IO events, and once that happens, the broadcast is sent to the corresponding handler, which is similar to the AWT thread
2.Handler is responsible for non-blocking behavior, similar to AWT actionlisteners; at the same time, it is responsible for binding handlers to event events, similar to AWT addActionListener



The Java NIO provides the basic mechanism for the implementation of the reactor pattern, and its selector informs us through Slectorkey when a channel has data, where we implement the binding of events and handler.

Let's take a look at the reactor pattern code:


public class Reactor implements runnable{

Final Selector Selector;
Final Serversocketchannel ServerSocket;

Reactor (int port) throws IOException {
selector = Selector.open ();
ServerSocket = Serversocketchannel.open ();
Inetsocketaddress address = new Inetsocketaddress (Inetaddress.getlocalhost (), port);
Serversocket.socket (). bind (address);    

Serversocket.configureblocking (false);
Register the Channel
Selectionkey SK =serversocket.register (selector,selectionkey.op_accept) with selector;

Logger.debug ("-->start serversocket.register!");    

//Use SK's attache function to bind acceptor if there is something that triggers acceptor
Sk.attach (New acceptor ());
Logger.debug ("-->attach (New acceptor ()!");
}


public void Run () {//normally in a new Thread
try {
while (! Thread.interrupted ())
{
Selector.select ();
Set selected = Selector.selectedkeys ();
Iterator it = Selected.iterator ();
Selector assumes that the channel has op_accept or read events, the following traversal occurs.
while (It.hasnext ())
An event to trigger a Accepter thread for the first time
Trigger Socketreadhandler later
Dispatch ((Selectionkey) (It.next ()));
Selected.clear ();
}
}catch (IOException ex) {
Logger.debug ("Reactor stop!" +EX);
}
}

Perform acceptor or Socketreadhandler
void Dispatch (Selectionkey k) {
Runnable r = (Runnable) (K.attachment ());
if (r! = null) {
R.run ();

}
}

Class Acceptor implements Runnable {//inner
public void Run () {
try {
Logger.debug ("-->ready for accept!");
Socketchannel C = serversocket.accept ();
if (c! = null)
Call handler to process channel
New Socketreadhandler (selector, c);
}
catch (IOException ex) {
Logger.debug ("Accept stop!" +EX);
}
}
}
}

The above code cleverly uses the Socketchannel attach function, which links hanlder with the channel that can occur, and when an event occurs, the handler of the corresponding link can be triggered immediately.

And look at the handler code:

public class Socketreadhandler implements Runnable {

public static Logger Logger = Logger.getlogger (Socketreadhandler.class);

Private Test test=new test ();

Final Socketchannel socket;
Final Selectionkey SK;

static final int READING = 0, sending = 1;
int state = READING;

Public Socketreadhandler (Selector sel, Socketchannel c)
Throws IOException {

socket = C;

Socket.configureblocking (FALSE);
SK = Socket.register (sel, 0);

The Run method of this class is called when the Selectionkey is bound to this handler and the next event is triggered.
See Dispatch (Selectionkey K)
Sk.attach (this);

At the same time, the Selectionkey is marked as readable for reading.
Sk.interestops (Selectionkey.op_read);
Sel.wakeup ();
}

public void Run () {
try{
Test.read (Socket,input);
Readrequest ();
}catch (Exception ex) {
Logger.debug ("Readrequest error" +ex);
}
}


/**
* Processing Read data
* @param key
* @throws Exception
*/
private void Readrequest () throws Exception {

Bytebuffer input = bytebuffer.allocate (1024);
Input.clear ();
try{

int bytesread = Socket.read (input);

......

Activate the thread pool to process these request
RequestHandle (New Request (SOCKET,BTT));

.....


}catch (Exception e) {
}

}

Notice in the handler inside again run a attach, so, cover the front acceptor, the next time the handler and the Read event occurs, will trigger the handler directly. This begins the process of reading and writing the data.

After the data has been read out, it is possible to make these data processing threads into a thread pool, so that the data is read out and thrown into the threads pools immediately, thus speeding up the processing speed:


Further, we are able to use multiple selector to handle connection and read events, respectively.

A high-performance Java Network Service mechanism will be formed, the exciting cluster parallel computing is about to be realized.


Two I/O 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-register the events and their event handlers (or callback functions) that need to be processed; 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. Reactor mode uses synchronous IO, while Proactor uses asynchronous IO.
In reactor, the event splitter is responsible for waiting for the file description descriptor or socket to be ready for read and write operations, then passing the ready event to the appropriate processor, and finally the processor is responsible for the actual read and write work.
In Proactor mode, the processor-or event splitter that is the processor-is only responsible for initiating asynchronous read and write operations. The IO operation itself is completed by the operating system. The parameters passed to the operating system need to contain the user-defined data buffer address and data size, from which the operating system can obtain the data required to write operations, or write data read from the socket. The event separator captures the IO operation completion event and then passes the event to the appropriate processor. For example, on Windows, the processor initiates an asynchronous IO operation, and the event splitter waits for the IoCompletion event. The typical asynchronous Pattern implementation is built on the operating system's support for asynchronous APIs, which we call "system-level" asynchronous or "true" async, because the application relies entirely on the operating system to run 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).
realization of Read in reactor
-Register read ready event and corresponding event handler
-Event Splitter Wait event
-the event arrives, activates the splitter, and the splitter invokes the event corresponding to the processor.
-the event handler finishes the actual read operation, processes the read data, notes a new event, and then returns control.
With For example the followingread process in Proactor (true async)Comparison:
-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 completed event.
-Event splitter waits for Operation complete event
-During the separator wait, the operating system runs the actual read operation with a parallel kernel thread and stores the resulting data in the user's own defined buffer, and finally notifies the event splitter that the read operation is complete.
-The event splitter calls the processor.
-the event handler processes the data in the user's own definition buffer, then initiates a new asynchronous operation and returns control to the event splitter.

Practice Status
The open source C + + development Framework ACE, developed by Douglas Schmidt and others, provides a large number of platform-agnostic, support for the underlying classes of concurrency (threads, mutually exclusive amounts, etc.), and at a high level of abstraction, two different sets of classes--ace reactor and ACE Proactor implementations. Only, although both are platform-independent, the interfaces provided vary.
ACE Proactor has a better performance on the Windows platform because Windows provides efficient asynchronous API support in the operating system (see Http://msdn2.microsoft.com/en-us/library/aa365198.aspx).
However, not all operating systems strongly support asynchrony at the system level. Like very many UNIX systems do not do. Therefore, on UNIX, it may be better to choose Ace Reactor resolution. In this way, for the best performance, Web application developers must maintain multiple codes for different operating systems: on Windows based on Ace Proactor, and on UNIX systems using ACE Reactor solutions.

Improvement Programme
In this section, we will try to address the challenge of building a portable framework for the Proactor and reactor models. In the improvement scenario, we move the read/write operation that was originally in the event handler to the splitter (it is better to call this idea "reactor"), which seeks to convert reactor multi-channel synchronous IO into analog asynchronous IO. Take a read operation as a sample, and improve the steps such as the following:
-Register the Read-ready event and its processor, and provide the data buffer address for the splitter, which is required to read the amount of data.
-Separator Wait events (such as Waiting on select ())
-Event arrival, activating separator. The separator runs a non-clogging read operation (it has all the information needed to complete the operation) and finally calls the appropriate processor.
-the event handler handles the user's own definition of the buffer data, register a new event (of course the same to give the data buffer address, the amount of data needed to read), and finally return control to the splitter.
As we can see, through the transformation of the multi-channel IO mode function structure, reactor is converted into proactor mode. Before and after the transformation, the actual workload of the model has not been added, only a slight exchange of responsibilities between the participants. Without a change in workload, it naturally does not impair performance. The comparison of the following steps, for example, can demonstrate the constant workload:
Standard/Typical reactor:
-Step 1: Wait for the event to arrive (reactor)
-Step 2: Distribute read-ready events to user-defined processors (reactor responsible)
-Step 3: Read the data (user processor is responsible)
-Step 4: Process data (user processor is responsible)
Improved implementation of simulation Proactor:
-Step 1: Wait for the event to arrive (Proactor)
-Step 2: Get a read-ready event to run the read data (now owned by Proactor)
-Step 3: Distribute the Read event to the user processor (Proactor responsible)
-Step 4: Process data (user processor is responsible)

For an operating system that does not provide an asynchronous IO API, this approach hides the interface details of the socket API, exposing a complete asynchronous interfaces externally. In this way, we can further build completely portable, platform-independent, universal external interface solutions.




Scalable IO in Java original

Principle and application of NIO

Developing a high-performance chat system with NIO

Socket for high-performance server

Many other NiO topic series discussed ....

Server back-end performance battle

Event-driven programming

Concurrency model

Rx (reactive Extensions) Introduction to reactive programming EDA2002 year of the Great God Address: http://www.jdon.com/concurrent/reactor.htm

NIO Learning 3--Basic model: Multiplexing model

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.