亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Netty 源碼閱讀入門實戰(四)-NioEventLoop

標簽:
Java

1  NioEventLoop概述

5bcedf480001e3f210000419.jpg

  • 总述


    5bcedf4900010d6210000323.jpg

2 NioEventLoop创建概述

5bcedf4c00019dba10000481.jpg


5bcedf4d0001527010000333.jpg


5bcedf4e0001d6c210000403.jpg


5bcedf4f0001de5810000116.jpg


5bcedf500001888810000107.jpg


5bcedf50000164e910000089.jpg


5bcedf5100018dbd10000125.jpg


5bcedf520001ab3310000131.jpg


1000


1000


对应


1000


1000


对应

1000


1000


对应

1000


1000


对应

1000

3 ThreadPerTaskThread

2 服务端Channel的创建

1000


1000


1000


1000


bind 对应样例的


1000

跟进调试


1000


1000


1000


1000


1000

通过反射创建的 channel


看看 channelFactory


1000


1000

  • 反射创建服务端 Channel


    1000


    首先


    1000


    1000


    1000

    创建完毕了


    1000


    1000


    1000

  • ANC


    1000


    1000


    1000


    1000


    1000


    1000


    1000

4 创建NioEventLoop线程

1000


1000


1000


1000


1000


1000


1000


1000


1000

5 创建线程选择器

1000


1000


1000


1000

  • 先看看普通的


    1000


    1000

  • 再看幂2的


    1000


    1000

    循环取数组索引下标,& 比取模性能更高

6 NioEventLoop的启动

1000


1000


1000


对应是


1000


1000


对应是

1000


1000


1000


1000


1000


1000


1000


1000


1000


1000


1000


1000


1000

7 NioEventLoop执行概述

8 检测IO事件

1000

1000


对应的源码为


1000


1000


1000


1000


1000


对应的源码为


1000


1000


1000

执行至此,说明已进行了一次阻塞式的 select 操作


1000

产生空轮询的判断


1000

当空轮询次数大于阈值


1000

阈值定义


1000


1000

阈值


1000


避免空轮询的再次发生


1000

创建新选择器


1000

获取旧选择器的所有 key 值


1000

netty 包装的 channel


1000

将之前的 key 事件解除,并绑定新的选择器和对应的事件


1000

更新选择器的 key


1000

至此,解决了空轮bug

9 处理IO事件

1000


1000


1000

原生JDK创建一个 selector


1000


1000

单线程处理,其实不需要两个数组,后续版本已经是一个数组


1000

只需关注


1000

根本不需要此三个方法


1000


1000

通过反射


1000

即此类


1000


1000

继续反射流程


1000

替换为优化后的 set 集合


一句话总结:用数组替换HashSet 的实现,做到 add 时间复杂度为O(1)


1000


1000


1000


1000


1000

 private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {        final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();        if (!k.isValid()) {            final EventLoop eventLoop;            try {
                eventLoop = ch.eventLoop();
            } catch (Throwable ignored) {                // If the channel implementation throws an exception because there is no event loop, we ignore this
                // because we are only trying to determine if ch is registered to this event loop and thus has authority
                // to close ch.
                return;
            }            // Only close ch if ch is still registerd to this EventLoop. ch could have deregistered from the event loop
            // and thus the SelectionKey could be cancelled as part of the deregistration process, but the channel is
            // still healthy and should not be closed.
            // See https://github.com/netty/netty/issues/5125
            if (eventLoop != this || eventLoop == null) {                return;
            }            // close the channel if the key is not valid anymore
            unsafe.close(unsafe.voidPromise());            return;
        }        try {            int readyOps = k.readyOps();            // We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
            // the NIO JDK channel implementation may throw a NotYetConnectedException.
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {                // remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
                // See https://github.com/netty/netty/issues/924
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);

                unsafe.finishConnect();
            }            // Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {                // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
                ch.unsafe().forceFlush();
            }            // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
            // to a spin loop
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                unsafe.read();                if (!ch.isOpen()) {                    // Connection already closed - no need to handle write.
                    return;
                }
            }
        } catch (CancelledKeyException ignored) {
            unsafe.close(unsafe.voidPromise());
        }
    }

Netty 默认通过反射将selector 底层的 HashSet 实现转为数组优化
处理每个 ketSet 时都会取到对应的 attachment,即在向 selector注册 io 事件时绑定的经过 Netty 封装后的 channel

10 -reactor线程任务的执行

1000


1000


1000


1000


1000


1000


1000


1000

定时任务


1000


1000


1000


1000


1000

从定时任务中拉取


1000


1000

根据时间,时间相同根据名称


1000

取nanotime 截止时间前的定时任务


1000


1000


1000

从普通 taskqueue 中取任务


1000



作者:芥末无疆sss
链接:https://www.jianshu.com/p/dd9afddaec08
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。


點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消