Previous article Portal:NioEventLoop executes select operation entry
We have learned about the relevant logic of executing the select() operation before. In this section, we continue to learn about the relevant logic of polling the io event:
NioEventLoop run() method:
protected void run() { for (;;) { try { switch ((selectNowSupplier, hasTasks())) { case : continue; case : //Poll io events (1) select((false)); if (()) { (); } default: } cancelledKeys = 0; needsToSelectAgain = false; //The default is 50 final int ioRatio = ; if (ioRatio == 100) { try { processSelectedKeys(); } finally { runAllTasks(); } } else { //Record the start time final long ioStartTime = (); try { //Processing the polled key(2) processSelectedKeys(); } finally { // Calculation time final long ioTime = () - ioStartTime; //Execute task(3) runAllTasks(ioTime * (100 - ioRatio) / ioRatio); } } } catch (Throwable t) { handleLoopException(t); } //Code omitted } }
Let's first look at the judgment if (ioRatio == 100). ioRatio is mainly used to control the ratio of the execution time of the processSelectedKeys() method and the execution time of the task queue. Among them, ioRatio is 50 by default, so it will go to the next step.
First record the start time through final long ioStartTime = () and then process the polled keys through processSelectedKeys() method.
processSelectedKeys() method
private void processSelectedKeys() { if (selectedKeys != null) { //flip() method will directly return the key array processSelectedKeysOptimized(()); } else { processSelectedKeysPlain(()); } }
We know that after the selector is optimized through netty, it will initialize the selectedKeys property, so if this property is not empty, it will go to the processSelectedKeysOptimized(()) method. This method is to operate according to the optimized selector.
If it is a non-optimized selector, the processSelectedKeysPlain(()) method will be entered
() is the array bound in selectedKey. We have mentioned in the previous section that selectedKeys are actually stored through arrays, so if you listen to the array of selectedKeys after select() operation, you will have a value if you listen to the event selectedKeys.
processSelectedKeysOptimized(()) method
private void processSelectedKeysOptimized(SelectionKey[] selectedKeys) { //Transfer the array through a for loop for (int i = 0;; i ++) { //Get the current selectionKey final SelectionKey k = selectedKeys[i]; if (k == null) { break; } //Set the current reference to null selectedKeys[i] = null; //Get channel(NioSeverSocketChannel) final Object a = (); //If it is AbstractNioChannel, then the processSelectedKey() method is called to handle the io event if (a instanceof AbstractNioChannel) { processSelectedKey(k, (AbstractNioChannel) a); } else { @SuppressWarnings("unchecked") NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a; processSelectedKey(k, task); } //Code omitted } }
First, iterate through a for loop through each key in the array. After obtaining the key, first clear the corresponding subscript in the array, because the selector will not be cleared automatically. This is the same as when we use a native selector, when we traversing the set of(), we need to execute remove() after getting the key.
Then obtain the channel registered on the key to determine whether the channel is AbstractNioChannel. Usually, the AbstractNioChannel is AbstractNioChannel, so the processSelectedKey(k, (AbstractNioChannel) a)
processSelectedKey(k, (AbstractNioChannel) a) method
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) { //Get unsafe in channel final unsafe = (); //If this key is not legal, it means there may be a problem with this channel if (!()) { //Code omitted } try { //If it is legal, get the io event of key int readyOps = (); //Link events if ((readyOps & SelectionKey.OP_CONNECT) != 0) { int ops = (); ops &= ~SelectionKey.OP_CONNECT; (ops); (); } //Write events if ((readyOps & SelectionKey.OP_WRITE) != 0) { ().forceFlush(); } //Read events and accept link events //If the current NioEventLoop is a work thread, this is the op_read event //If the current NioEventLoop is the boss thread, this is the op_accept event if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { (); if (!()) { return; } } } catch (CancelledKeyException ignored) { (()); } }
We first get the unsafe bound to the channel, and then get the channel registration event
We pay attention
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0)
I believe this judgment is written in the comments very clearly. If the current NioEventLoop is a work thread, this is the op_read event. If the current NioEventLoop is a boss thread, this is the op_accept event
Then the read() method will be executed through the channel-bound unsafe object to handle links or read and write events
The above is the process of NioEventLoop handling io events. The execution logic of the read() method will be analyzed in detail in future chapters. For more information about Netty NioEventLoop handling IO event logic, please pay attention to my other related articles!