netty nio event loop group

netty event executor group and event executor definition and abstract implementation: http://donald-draper.iteye.com/blog/2391257
netty multi-threaded event executor group: http://donald-draper.iteye.com/blog /2391270
netty multithreaded event loop group: http://donald-draper.iteye.com/blog/2391276
netty abstract scheduling event executor: http://donald-draper.iteye.com/blog/2391379
netty single-threaded event Executor initialization: http://donald-draper.iteye.com/blog/2391895
netty single-threaded event executor executes tasks with graceful shutdown: http://donald-draper.iteye.com/blog/2392051
netty single-threaded Event loop: http://donald-draper.iteye.com/blog/2392067
netty nio event loop initialization: http://donald-draper.iteye.com/blog/2392161
netty nio event loop follow-up: http://donald -draper.iteye.com/blog/2392264
Introduction:
We looked at the Nio event loop in the previous article, so let's review:
    There is a deselect key counter cleaning interval CLEANUP_INTERVAL inside the Nio event loop, which is used to reset the deselect key counter canceledKeys (int) when the number of deselected keys reaches 256, and re-select the operation; the selector automatically reconstructs the threshold SELECTOR_AUTO_REBUILD_THRESHOLD , the default selection operation occurs 512 times, which is used to control how many times the selection operation occurs in the selector, and the selector is reconstructed; the selector state judger selectNowSupplier is used to obtain the selection operation result of the selector inside the Nio event loop; at the same time, there is a The selector selector, the unwrapped selector unwrappedSelector and a selector provider provider, a selection key ready set selectedKeys (SelectedSelectionKeySet); when the selector's selection operation is blocked, the wakeUp (AtomicBoolean) property determines whether it should break the selection operation process ; The time ratio of a Nio processing Io event ioRatio(int), the default is 50, that is, the IO event processing time and other event processing time each account for half of the Nio event loop; a selection strategy selectStrategy is used to control the selection loop, if the returned result is -1, the next step should block the selection operation. If the return result is -2, the next step should be to call back to the IO event loop to process the IO event instead of continuing to perform the selection operation. The return value is greater than 0, indicating that work needs to be done. , that is, the selected channel registered to the selector has an IO event ready.
    The Nio event loop initialization is mainly to pass the Nio event loop group, event executor and task rejection policy to the parent class single-threaded event loop (single-threaded event executor), and open a selector at the same time.
    Open the selector process, delegate to the selector provider to open a selector, if you need to optimize the selector, under the current thread access control selection, load the selector implementation class, do not initialize, if the selection key loaded from the system class loader The implementation class is not a Class instance, or is not a bare selector type, no selector key set optimization is performed, and the selector is a bare selector opened by the selector provider; otherwise, the system selector implementation is obtained under the same access control permission of the current thread Class, selector-ready key set selectedKeysField and its proxy publicSelectedKeysField, set the selector-ready key set selectedKeysField and its proxy publicSelectedKeysField access control permissions, set the system selector's ready key set selectedKeysField and its proxy publicSelectedKeysField to selectedKeySet (SelectedSelectionKeySet), And wrap the selector selector as SelectedSelectionKeySetSelector.
    After the Nio event loop is started, the selection strategy first generates the next operation strategy according to the selector result provider and whether there are tasks in the task queue. If the selection operation result returns SelectStrategy.CONTINUE, it will jump out of the current event loop. If it is SelectStrategy.SELECT, Then execute the selection operation, and block the next selection operation. If you need to wake up the selector, wake up; then reset the canceled selection key counter canceledKeys to 0, set whether the need to reselect the property needsToSelectAgain to false, and then process the selection key that the selector is ready for , According to the current IO event processing time percentage ioRatio, decide whether to execute all tasks in the task queue or execute the task queue task over time. If the ioRatio is less than 100, the task in the task queue is executed over time; finally, check whether the event loop is closing, and it is the opposite. Register the selection channel in the selector and close it, confirming that the event loop is closed; the whole process above is repeated continuously during the operation of the event loop. In each processing of the event loop, at the end check to see if the event loop is closed, if it is closing, close all channels registered to the selector and make sure the event loop is closed.
    The process of the selection operation is: first reset the selection operation counter to 0, and calculate the selection operation delay time; if the delay time has passed 0.5 milliseconds, and the selection operation counter is currently 0, that is, the selection operation is performed for the first time, and the execution is executed immediately. Select operation, update the selection operation counter, and jump out of the current selection operation process; if there is a task in the task queue, and the wakeUp property is false, and the update to true is successful, the selection operation is executed immediately, the selection operation counter is updated, and the current selection operation process is jumped out ; If neither of the above two cases is true, the timeout selection operation is performed. If the selection key is ready, or the original wakeUp property is true, or the current wakeUp property is true, or the task queue has tasks, or the scheduling task queue has scheduling tasks, then Jump out of the current selection operation; if the selector reconstruction threshold is greater than 0, and the value of the current selection operation counter is greater than the threshold, the selector is reconstructed, that is, a new selector is created to register the selection key associated with the original selector to the new selection. in the device.
    The default processing selector is ready to select the key set process, select the key set for traversal, and process the ready selection key. First, the selected key must be currently valid, and then it is judged whether the selected key channel event loop is the current loop, otherwise it returns directly, and it is judged to be ready. The ready event of the key is a connection request event, a write event or a read event. If the event is connected, the Unsafe of the entrusted channel will complete the channel connection and remove the connection event; if it is a write event, the Unsafe of the entrusted channel will refresh the write request Queue, release memory; if it is a read event, delegate to the Unsafe read method of the channel; if the selection operation needs to be re-executed in the process of processing the ready selection key, it will be executed immediately, and the current ready selection key set and its iterator will be updated .
    There is a selector inside the Nio event loop, and all channels registered to the selector are in one event loop. The Nio event loop is a single-threaded event loop, that is, a single-threaded event executor. When processing the ready selection key of the selector, when And only when the event loop where the key-related channel is ready is the current event loop, the ready IO event of the ready-select key-related channel will come out, so as to ensure the thread safety of operations such as read and write of the channel.
    The actual work of the Nio event loop is to perform the selection operation and process the ready selection key of the selector. The Nio event loop is somewhat similar to Mina's IoProcessor. Both can look at a thread executor and execute the IO event operation of the channel, but the difference is Nio manages the selector Selector, and Mina's IoProcessor manages the session IoSession.

Today we take a look at the Nio event loop group NioEventLoopGroup:
package io.netty.channel.nio;

import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import io.netty.channel.DefaultSelectStrategyFactory;
import io.netty.channel.MultithreadEventLoopGroup;
import io.netty.channel.SelectStrategyFactory;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.EventExecutorChooserFactory;
import io.netty.util.concurrent.RejectedExecutionHandler;
import io.netty.util.concurrent.RejectedExecutionHandlers;

import java.nio.channels.Selector;
import java.nio.channels.spi.SelectorProvider;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;

/**
 * {@link MultithreadEventLoopGroup} implementations which is used for NIO {@link Selector} based {@link Channel}s.
 The nio event loop group is actually a multi-threaded event loop group used to manage channel-based selectors
 */
public class NioEventLoopGroup extends MultithreadEventLoopGroup {

    /**
     * Create a new instance using the default number of threads, the default {@link ThreadFactory} and
     * the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
     Create a default number of threads, the default thread factory selector provider nio event loop group, if the io.netty.eventLoopThreads system property is not configured,
     The default number of threads is 2 times the number of processors, see#MultithreadEventLoopGroup
     */
    public NioEventLoopGroup() {
        this(0);
    }

    /**
     * Create a new instance using the specified number of threads, {@link ThreadFactory} and the
     * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
     Create an event loop group with the specified number of threads
     */
    public NioEventLoopGroup(int nThreads) {
        this(nThreads, (Executor) null);
    }
    //These structures are all simple, not explained one by one see##MultithreadEventLoopGroup
    /**
     * Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the
     * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
     */
    public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
        this(nThreads, threadFactory, SelectorProvider.provider());
    }

    public NioEventLoopGroup(int nThreads, Executor executor) {
        this(nThreads, executor, SelectorProvider.provider());
    }

    /**
     * Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the given
     * {@link SelectorProvider}.
     */
    public NioEventLoopGroup(
            int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider) {
        this(nThreads, threadFactory, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
    }

    public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory,
        final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) {
        super(nThreads, threadFactory, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
    }

    public NioEventLoopGroup(
            int nThreads, Executor executor, final SelectorProvider selectorProvider) {
        this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
    }

    public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory) {
        super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
    }

    public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
                             final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory) {
        super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory,
                RejectedExecutionHandlers.reject());
    }

    public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
                             final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory,
                             final RejectedExecutionHandler rejectedExecutionHandler) {
        super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, rejectedExecutionHandler);
    }
    /**
     * Sets the percentage of the desired amount of time spent for I/O in the child event loops.  The default value is
     * {@code 50}, which means the event loop will try to spend the same amount of time for I/O as for non-I/O tasks.
     Set the IO event processing time percentage of the nio event loop group
     */
    public void setIoRatio(int ioRatio) {
        / / Traverse the event loop group, set the IO event processing time percentage of the nio event loop
        for (EventExecutor e: this) {
            ((NioEventLoop) e) .setIoRatio (ioRatio);
        }
    }

    /**
     * Replaces the current {@link Selector}s of the child event loops with newly created {@link Selector}s to work
     * around the  infamous epoll 100% CPU bug.
     Refactoring the nio event loop group selector
     */
    public void rebuildSelectors() {
        // Traverse the event loop group and refactor the selector of the nio event loop
        for (EventExecutor e: this) {
            ((NioEventLoop) e).rebuildSelector();
        }
    }
    //Create Nio event loop
    @Override
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        return new NioEventLoop(this, executor, (SelectorProvider) args[0],
            ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
    }
}

As can be seen from the above, the nio event loop group is actually a multi-threaded event loop group, which is mainly used to manage the nio event loop; from setting the IO event processing time percentage of the nio event loop group
and reconstructing the nio event loop group selector method, It can be seen why the event loop group inherits iterators; the nio event loop group can uniformly set the IO event processing time percentage of the nio event loop in the group,
and the nio event can dynamically change its own IO event processing time percentage and reconstruct the selector. It also means that.
The nio event loop group is multi-threaded, while the nio event loop is single-threaded, which is a bit like the relationship between Mina's IoProcessor and processor.
public interface EventLoopGroup extends EventExecutorGroup {

public interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor> {




Let's look at the construction:
public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
                         final SelectorProvider selectorProvider,
                         final SelectStrategyFactory selectStrategyFactory,
                         final RejectedExecutionHandler rejectedExecutionHandler) {
    super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, rejectedExecutionHandler);
}

//MultithreadEventLoopGroup
/**
 * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor,
 * EventExecutorChooserFactory, Object...)
 */
protected MultithreadEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
                                 Object... args) {
    super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, chooserFactory, args);
}

The parameter args is the selector provider, the selection strategy factory, and the refusal to execute the strategy, which is passed to the parent class. Let's look down to see who these parameters are given?
//MultithreadEventExecutorGroup
 
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
       ...
        children = new EventExecutor[nThreads];
        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
	        //The key here is to create an event executor
                children[i] = newChild(executor, args);
                success = true;
         }
	...
}
/**
 * Create a new EventExecutor which will later then accessible via the {@link #next()}  method. This method will be
 * called for each thread that will serve this {@link MultithreadEventExecutorGroup}.
 * To be extended by subclasses
 */
protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;

Back to the nio event loop group:
there is a newChild method that returns the nio event loop, which is a single-threaded event loop (single-threaded event executor)

//Create a Nio event loop
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    return new NioEventLoop(this, executor, (SelectorProvider) args[0],
        ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}

At this point, we see the args parameter above, and the event is passed to the Nio event loop.

Let's take a look at the selection policy factory:
public NioEventLoopGroup(
            int nThreads, Executor executor, final SelectorProvider selectorProvider) {
        this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

//DefaultSelectStrategyFactory
public final class DefaultSelectStrategyFactory implements SelectStrategyFactory {
    public static final SelectStrategyFactory INSTANCE = new DefaultSelectStrategyFactory();

    private DefaultSelectStrategyFactory() { }

    @Override
    public SelectStrategy newSelectStrategy() {
        return DefaultSelectStrategy.INSTANCE;
    }
}

//DefaultSelectStrategy
package io.netty.channel;

import io.netty.util.IntSupplier;

/**
 * Default select strategy.
 */
final class DefaultSelectStrategy implements SelectStrategy {
    static final SelectStrategy INSTANCE = new DefaultSelectStrategy();

    private DefaultSelectStrategy() { }
    //Get the current state of the selector
    @Override
    public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
        //If there is a task, return the result value selected by the selector, otherwise return to SelectStrategy.SELECT
        return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;
    }
}

As can be seen from the above, the default selection strategy DefaultSelectStrategy, the strategy method mainly determines the work of the first step according to whether there are tasks in the task queue.
If there is no task, the selection operation is performed in the next step, otherwise the result value after the selector selection operation is returned. , do not perform the selection operation, and then process the operation ready selection key and
tasks in the task queue.
Summary:
The nio event loop group is actually a multi-threaded event loop group, which is mainly used to manage the nio event loop; from setting the IO event processing time percentage of the nio event loop group and reconstructing the nio event loop group selector method, it can be seen that the event The reason why the loop group inherits iterators; the nio event loop group can uniformly set the IO event processing time percentage of the nio event loop in the group, and the nio event can dynamically change its own IO event processing time percentage. Refactoring selectors also have such a meaning . The nio event loop group is multi-threaded, while the nio event loop is single-threaded, which is a bit like the relationship between Mina's IoProcessor and processor. The difference is that the nio event loop is oriented to the selector Selector, while the processor is oriented to the session IoSession.

Guess you like

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