Reactor mode

What is the Reactor pattern?

    The Reactor pattern is an event-driven design pattern. The Reactor framework is the most basic framework among the various ACE frameworks, and other frameworks use the Reactor framework more or less. 
      In an event-driven application, the service requests of one or more clients are demultiplexed and dispatched to the application. In event-driven applications, multiple service requests received at the same time are processed synchronously and in an orderly manner. 
      The reactor mode is somewhat similar to the Appearance mode. However, the Observer pattern is associated with a single event source, while the Reactor pattern is associated with multiple event sources. When a subject changes, all dependents are notified.

    Initialization Dispatcher : used to manage Event Handler, define registration, remove EventHandler, etc. The entry of Reactor mode calls the select method of Synchronous Event Demultiplexer to block and wait for the event to return. When blocking and waiting for the return, the Initiation Dispatcher is notified when the event occurs, and then the Initiation Dispatcher calls the event handler to process the event, that is, the handle_event() method in the EventHandler is called back.

    Synchronous Event Demultiplexer (Synchronous Event Demultiplexer) : Infinite loop waiting for the arrival of new events, once a new event is found, it will notify the initial event dispatcher to call a specific event handler.

    System handler (Handles) : The handle in the operating system is an abstraction of resources at the operating system level, which can be an open file, a connection (Socket), a Timer, etc. Since the Reactor mode is generally used in network programming, it generally refers to Socket Handle, which is a network connection (Connection, Channel in Java NIO). This Channel is registered in the Synchronous Event Demultiplexer to monitor events that occur in the Handle. It can be a CONNECT event for ServerSocketChannel, or READ, WRITE, and CLOSE events for SocketChannel.

   Event Handler : Defines event handling methods for use by Initialization Dispatcher callbacks.

    Concrete Event Handler : The actual implementation of the event handler, and a Handle is bound. Because in practice, we often have more than one event handler, so the event handler interface and implementation are separated here, which is similar to polymorphism in high-level languages ​​such as C++ and Java.

module interaction

    1) We register the Concrete Event Handler to the Initiation Dispatcher. 
    2) The Initiation Dispatcher calls the get_handle interface of each Event Handler to obtain its bound Handle. 
    3) The Initiation Dispatcher calls handle_events to start the event processing loop. Here, the Initiation Dispatcher will collect all the Handles obtained in step 2, and use the Synchronous Event Demultiplexer to wait for the events of these Handles to occur. 
   4) When a certain (or certain) Handle event occurs, Synchronous Event Demultiplexer notifies the Initiation Dispatcher. 
    5) The Initiation Dispatcher finds the corresponding Handler according to the Handle of the event. 
    6) The Initiation Dispatcher calls the handle_event method of the Handler to process the event.

The single-threaded version of the Reactor pattern

    All requests from the client are processed by a dedicated thread. This thread wirelessly loops to monitor whether another client's request arrives. Once the client's request is received, it is distributed to the responding processor for processing.

Worker threads are implemented using thread pools

Considering the reuse of worker threads, the worker threads are designed as thread pools.

Reactor advantages

1) Fast response, no need to be blocked by a single synchronization time, although the Reactor itself is still synchronized; 
2) The programming is relatively simple, which can avoid complex multi-threading and synchronization problems to the greatest extent, and avoid multi-thread/process switching overhead ; 
3) Scalability, you can easily make full use of CPU resources by increasing the number of Reactor instances; 
4) Reusability, the reactor framework itself has nothing to do with specific event processing logic, and has high reusability;


Reactor Disadvantages

1) Compared with the traditional simple model, Reactor adds a certain complexity, so it has a certain threshold and is not easy to debug. 
2) 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. 
3) The Reactor mode is still implemented in the same thread when IO reads and writes data. Even if multiple Reactor mechanisms are used, if there is a long-term data read and write in the Channel that shares a Reactor, it will affect the Reactor. The corresponding time of other Channels, such as when large files are transferred, the IO operation will affect the corresponding time of other Clients, so for this kind of operation, using the traditional Thread-Per-Connection may be a better choice, or at this time Use Proactor mode.

Summarize

    The reactor mode is the implementation principle of javaNIO non-blocking technology. We not only need to know its principle process, but also its code implementation. Of course, this reactor mode is not only implemented in NIO, but also appeared in other places such as redies, indicating this mode It is still more practical, especially in the case of multi-threading and high concurrency.

Simple implementation of source code

import java.io.IOException;  
import java.net.InetAddress;  
import java.net.InetSocketAddress;  
import java.nio.channels.SelectionKey;  
import java.nio.channels.Selector;  
import java.nio.channels.ServerSocketChannel;  
import java.util.Iterator;  
import java.util.Set;  

/** 
 * 反应器模式 
 * 用于解决多用户访问并发问题 
 *  
 * 举个例子:餐厅服务问题 
 *  
 * 传统线程池做法:来一个客人(请求)去一个服务员(线程) 
 * 反应器模式做法:当客人点菜的时候,服务员就可以去招呼其他客人了,等客人点好了菜,直接招呼一声“服务员” 
 *  
 */  
public class Reactor implements Runnable{  
    public final Selector selector;  
    public final ServerSocketChannel serverSocketChannel;  

    public Reactor(int port) throws IOException{  
        selector=Selector.open();  
        serverSocketChannel=ServerSocketChannel.open();  
        InetSocketAddress inetSocketAddress=new InetSocketAddress(InetAddress.getLocalHost(),port);  
        serverSocketChannel.socket().bind(inetSocketAddress);  
        serverSocketChannel.configureBlocking(false);  

        //向selector注册该channel    
        SelectionKey selectionKey=serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);  

        //利用selectionKey的attache功能绑定Acceptor 如果有事情,触发Acceptor   
        selectionKey.attach(new Acceptor(this));  
    }  

    @Override  
    public void run() {  
        try {  
            while(!Thread.interrupted()){  
                selector.select();  
                Set<SelectionKey> selectionKeys= selector.selectedKeys();  
                Iterator<SelectionKey> it=selectionKeys.iterator();  
                //Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。  
                while(it.hasNext()){  
                    //来一个事件 第一次触发一个accepter线程    
                    //以后触发SocketReadHandler  
                    SelectionKey selectionKey=it.next();  
                    dispatch(selectionKey);  
                    selectionKeys.clear();  
                }  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  

    /** 
     * 运行Acceptor或SocketReadHandler 
     * @param key 
     */  
    void dispatch(SelectionKey key) {  
        Runnable r = (Runnable)(key.attachment());    
        if (r != null){    
            r.run();  
        }    
    }    

}  
import java.io.IOException;  
import java.nio.channels.SocketChannel;  

public class Acceptor implements Runnable{  
    private Reactor reactor;  
    public Acceptor(Reactor reactor){  
        this.reactor=reactor;  
    }  
    @Override  
    public void run() {  
        try {  
            SocketChannel socketChannel=reactor.serverSocketChannel.accept();  
            if(socketChannel!=null)//调用Handler来处理channel  
                new SocketReadHandler(reactor.selector, socketChannel);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}  
import java.io.IOException;  
import java.nio.ByteBuffer;  
import java.nio.channels.SelectionKey;  
import java.nio.channels.Selector;  
import java.nio.channels.SocketChannel;  

public class SocketReadHandler implements Runnable{  
    private SocketChannel socketChannel;  
    public SocketReadHandler(Selector selector,SocketChannel socketChannel) throws IOException{  
        this.socketChannel=socketChannel;  
        socketChannel.configureBlocking(false);  

        SelectionKey selectionKey=socketChannel.register(selector, 0);  

        //将SelectionKey绑定为本Handler 下一步有事件触发时,将调用本类的run方法。    
        //参看dispatch(SelectionKey key)    
        selectionKey.attach(this);  

        //同时将SelectionKey标记为可读,以便读取。    
        selectionKey.interestOps(SelectionKey.OP_READ);    
        selector.wakeup();  
    }  

    /** 
     * 处理读取数据 
     */  
    @Override  
    public void run() {  
        ByteBuffer inputBuffer=ByteBuffer.allocate(1024);  
        inputBuffer.clear();  
        try {  
            socketChannel.read(inputBuffer);  
            //激活线程池 处理这些request  
            //requestHandle(new Request(socket,btt));   
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}  

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326358375&siteId=291194637