NiO learns 3--the demo base: multiplexer mode

Source: Internet
Author: User

Reactor mode and NIO

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

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 design of classic network services for example with. The processing of the data is completed in each thread:

However, such a pattern will degrade very quickly when the user load is added. Again we need to find a new solution to keep the data flowing smoothly. Very clearly. The event triggering mechanism is the best solution, and when an event occurs, it touches the handler and then begins processing the data.

Reactor mode is similar to event handling in AWT:

Reactor Model participant

1.Reactor is responsible for responding to IO events. Once it 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, which is responsible for binding handlers to event events at the same time, similar to AWT addActionListener



The Java NIO provides the basic mechanism for the implementation of the reactor pattern, and its selector is communicated to us by Slectorkey when it discovers that a channel has data. Here 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 suppose there is something.    Trigger 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 Socketchannel's attach function is cleverly used in the above code to link Hanlder with the channel where events can occur. 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.

Once the data has been read out, it can be made into a thread pool so that when the data is read out, it is immediately thrown into the sink. This accelerates 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 adopts synchronous IO. and 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. The operating system talent obtains the data required to write operations, or writes 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. The event splitter waits for the IoCompletion event again. A typical asynchronous Pattern implementation is 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 run real IO work.


Give me a sample example. will help to understand the difference between reactor and Proactor, as an example of a read operation (similar to a class operation).


implement 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.
Compared to the read process in Proactor (true async) such as the following:
-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 process. The operating system runs the actual read operation using a parallel kernel thread. The result data is stored in the user's own definition buffer, and the event splitter is finally notified 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.

It's just that. Although both are platform independent, the interfaces provided vary.


ACE Proactor provides superior performance on Windows platforms. 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. But in this way, for the best performance, Web application developers must maintain multiple codes for different operating systems: on Windows, on the basis of Ace Proactor. The UNIX system uses ACE reactor solution.

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 moved the read/write operation that was originally in the event handler to the splitter (or, preferably, the idea of "reactor"), seeking to convert reactor multi-sync IO to 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 ())
-the event arrives. Activates the 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 operating systems that do not provide asynchronous IO APIs. Such an approach could hide the interface details of the socket API, exposing a complete asynchronous port.

This allows us to further build completely portable, platform-independent. There is a common external interface to solve the method.




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

Copyright notice: This article Bo Master original articles, blogs, without consent may not be reproduced.

NiO learns 3--the demo base: multiplexer mode

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.