博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Netty 源码阅读入门实战(四)-NioEventLoop
阅读量:6446 次
发布时间:2019-06-23

本文共 3525 字,大约阅读时间需要 11 分钟。

1 NioEventLoop概述

img_3e4785299a22452f236c5bd807c8ba8d.png
  • 总述

    img_894ae143336480cafb294fb7b7eb754c.png

2 NioEventLoop创建概述

img_53fb576085d067dd6b85a64fa752e202.png
img_4fd551a1189d5ac095ed889678dd1b67.png
img_5e5d043ebe0111676b4f2860d25261cf.png
img_923eb37fc5c4bb2224baa47dcf058ee3.png
img_6be0b71801960103d81bbe47127294a9.png
img_db4a8bbe9a6ebfb30cfb3a510aef3ca0.png
img_8ef94f14216d84311f57149372048afd.png
img_c7a73c17629efc66508bd362624893b0.png
img_0627868028fcfe3152c953910394f9bc.png
img_9e7f882f0332b40e8387d1514672a39e.png

对应

img_56ca0ac8e30e014d84b36af1984d58ad.png
img_d4557d5ffc8691d0d3292e672422afe8.png
对应
img_1b5faa6d6a8d3e524ab9da0bd97909c1.png
img_8e7efd6855fbe93cb9cc09d3bbb7842f.png
对应
img_216ffbe3c7f58f01e31921a4bf9c1600.png
img_d3f37a76e9ccef688431c71d06570323.png
对应
img_e70c942dfd72b8ce1c724db50533bd72.png

3 ThreadPerTaskThread

2 服务端Channel的创建

img_d90f7ad5065ed6dcfdf00386f55d2b5a.png
img_1623de9d6ac7bd6458269b7de174270e.png
img_8d2048306cf000a168b99de798195cbd.png
img_97516cbde3eca1b3408382d727d5ecba.png

bind 对应样例的

img_0a486ac537cbfbc776082274e8dbaa1d.png
跟进调试
img_00a649bb1a1159786692b05ad0893317.png
img_a5e4e8927e31bb0ae9468cec0715c2df.png
img_bbb42f0d6b2c6dbd8ced76e111baf958.png
img_24a3ee1159a8440cf8214f8951cec913.png
img_a502e1e10677215724526a1d1d68fdd9.png
通过反射创建的 channel

看看 channelFactory

img_5cd17ac276cc3e7558e54cf3ace25860.png
img_b778f680d274e1abea3cf7076b235924.png
  • 反射创建服务端 Channel

    img_50c088795c1708bcc39ba8194a2b4f4b.png

    首先

    img_9296bb35cd2e94366cb132a3d4c27e81.png
    img_468901ac926279cdabaa6820e94e511a.png
    img_323f4fca1c5e6a242346b5443c590581.png
    创建完毕了
    img_2482e50e588146334404aeffdec67718.png
    img_a01a99a9ad2f4af7cb2cf40625a859a2.png
    img_049b55ed9cb8268f217e94c5ba71220d.png
  • ANC

    img_4a5d2de4d095cf6e73583ce2b0de9279.png
    img_e187867d5261ed0e2c974694e90027bc.png
    img_4c49db79e4b43fc7089cdb4cdc0519ab.png
    img_6f1bf73adb85d5248fdec448df542c7c.png
    img_dd0eea4afcaad6de1b301c39e9d2d728.png
    img_425cdab272babe3736b3e0cb6a643a7c.png
    img_07ba31e5e82cf5669ce171063ceac8cb.png

4 创建NioEventLoop线程

img_2da0e7afef0ef694035d6f9d6ed1b771.png
img_f2f31c12374dc22a11a6853c2cce518d.png
img_c7e16a985607241f2c23a1313fb17506.png
img_bfd458e96d7ab387532b511092771beb.png
img_54cba9ccb044d443e78dc09731a69269.png
img_d8a349681821446f8338162ebab2d548.png
img_fdab4fd5755fe08eb4d488053fea02e7.png
img_e153b220ee55deeb3838db5afd03abce.png
img_a517b472b16f5ceb9e6c90c78fd1c250.png

5 创建线程选择器

img_0b8f0b9fd0eba85c6e62d6162936ec6e.png
img_47295f9db325de2cebf12fe07a33aa15.png
img_9c87a458914e9d253c3ed305f6f2f838.png
img_a91b415259c9a060a2d94bec2dddfeed.png
  • 先看看普通的

    img_204ee1739ca0b0401df1e18c989ae7a0.png
    img_440fe0a42d45d4d307fa1c0d6c2b03b5.png
  • 再看幂2的

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

6 NioEventLoop的启动

img_65060a73b49b134941a62a72a0e41b67.png
img_c7d6e34acce07a894aa906902c672d2a.png
img_498762120ee101e3e97716e0644be1bb.png

对应是

img_ba46d65e596d2e83bcfc8e031695e55a.png
img_aede86f3dd6ac70d8656d97e41b68f72.png
对应是
img_e4ca09089cd9d7ff88f40cfd481872d2.png
img_d32113cb801e680d37fb9ae4bd08e2d0.png
img_9d72563fb488cfbb4b56ba4bc964e77c.png
img_1eff0444dd6f1a1527bb7ba9dcc8404d.png
img_198dd93d64e992cbb8193e4a4a8a66b5.png
img_95138239a20556fd366a27942a8ded49.png
img_73d16fa11b66a419bff329ae4f9db4f0.png
img_7cc935722fac620d8b22f59f861b4dbc.png
img_0e1152fdd5ddc1bc63c2dbfa34664bd7.png
img_61fbde07e980812b8a5b698ee67220b6.png
img_e753b40e799240a0ec7c1babbc7a8763.png
img_8a497d398c55905cc7f02e6af37afec5.png
img_e94c77712cdcbe30ce6cabbec34541dc.png

7 NioEventLoop执行概述

8 检测IO事件

img_c1033feeeb1edaf9d3d4c012fb1263f5.png
img_e0891ff76d9b693a5713a01f81271f41.png

对应的源码为

img_5b85e3590552270665313b0a5879b61c.png
img_54a45e93cd117d0f2af79bc9f51ad383.png
img_c95e3d7f34a905627f0c77605087d822.png
img_61f78d919dfe4f8c9e34e6cc3277713c.png
img_35bc109c694ece683d4514ef98cc17d9.png

对应的源码为

img_382a3463ff1de840c1a1b159542c4305.png
img_4165a6fd9641ce3f326bf7263fd941d8.png
img_37994cc629904c85a98d2fa69e2b2576.png
执行至此,说明已进行了一次阻塞式的 select 操作
img_9401e624538e59d888c7894fbe3225ca.png
产生空轮询的判断
img_b5f8065ca29adc3151c9c0b3d141d95c.png
当空轮询次数大于阈值
img_1004360436bd9c6e23569c2bac4a8a42.png
阈值定义
img_1ee5c435ca80c6a58cd47348b084dbe4.png
img_0a688cd41c789b1004a6cf874909b51e.png
阈值
img_5005ab355dca47877c98ea528a369f31.png

避免空轮询的再次发生

img_3c644bc1ddcb4049162fa6383f3ea5cb.png
创建新选择器
img_eb2537762ad5ccad1148cdc379bd2670.png
获取旧选择器的所有 key 值
img_26106e9505a176f5a9f958fdae59511d.png
netty 包装的 channel
img_3f30ee3f507d41b5af0d6f2799b147d5.png
将之前的 key 事件解除,并绑定新的选择器和对应的事件
img_7372b6cd0cefd8d54cb1c63a348f7cfd.png
更新选择器的 key
img_bb65dd483c6f82727a1bc16a05f57309.png
至此,解决了空轮bug

9 处理IO事件

img_fd03c691501a0c25885550682ba1bd8d.png
img_0ba37ad091015deac5e31fd9221bfcba.png
img_39d052f3827a48a2e31d819087c1177e.png
原生JDK创建一个 selector
img_965ba11c640f31dc4125f70f1b862f40.png
img_5b9384b9e7e36d3c6b417ff49560fdf0.png
单线程处理,其实不需要两个数组,后续版本已经是一个数组
img_42e7771d45565c74346cdde91e26e9c7.png
只需关注
img_133774a2695959973277e72fc024a5db.png
根本不需要此三个方法
img_e469f54619c99f088934d5fcdf8ab0d1.png
img_77abc4ac64c6a4cc1e3a28660b094eb0.png
通过反射
img_907ddb46ff96367dc6d7982f0d588b72.png
即此类
img_be97f28158930993f578632ce87fa89c.png
img_b22b329da7f6c89b1a61accbd8266493.png
继续反射流程
img_889585a38aa465cedb558a8a830b67a5.png
替换为优化后的 set 集合

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

img_c5ad660d7b871d50358198101c2f1845.png
img_ac98eef51b944d6f91a9e31eeed7afd1.png
img_0d7f77f74af1e826ab786f4792a0d9bc.png
img_395f97c37d7704f001f570a3e1da6516.png
img_1548846e57b6d47a7fc39059e812822d.png
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线程任务的执行

img_d23531f3224a2d31cdb3858e2aa42057.png
img_b5b4f34ff495d0656a9b1c0e65e1c9fd.png
img_8b21f0bd17294cf0dbbe103a9b9f8922.png
img_56bae058c9e2c790f753805a9706d7d4.png
img_e2c45258dd345a4692da4d5cec464516.png
img_a2d489961a756d9c5e719ab487df9374.png
img_963832f921026cba097fc6856b2aa3d0.png
img_265750faea00d304829ac7799c846428.png
定时任务
img_31c0c67984722ca5fabf0819840c362f.png
img_881fa2c9e3d74ad8076bcc3e3cb16e03.png
img_c095536dc17b1669781ee866e99884c1.png
img_dbc11182ff1f6ab5f9b55536a4293920.png
img_bbe94ed8f724dfe331369c0b6f94898a.png
从定时任务中拉取
img_b67416cae0726a23d44fa1ff16f7cb39.png
img_bb45580e58227f60a045c952d9e100d7.png
根据时间,时间相同根据名称
img_6684d628a9ba7408c147c2de6cdd07b1.png
取nanotime 截止时间前的定时任务
img_2e858d56ec5a823b00eb4f469244aa25.png
img_41bbfe21db0e70353a4b34f31905cde6.png
img_6d8e64f40916a99ea0663a7a851be9b9.png
从普通 taskqueue 中取任务
img_94c627eb719fd029af84268b0e814863.png

转载地址:http://njvwo.baihongyu.com/

你可能感兴趣的文章
超级账本Fabric区块链用弹珠游戏Marbles 部署
查看>>
常用的正则表达式
查看>>
第10讲——名称空间
查看>>
springcloud 之 配置中心服务 spring cloud config
查看>>
Ubuntu 18.04修改IP地址
查看>>
更改mysql数据库所在目录
查看>>
在 IIS6 中使用 GZIP
查看>>
Powershell DSC 5.0 - 资源的使用
查看>>
力求企业的内部公平性
查看>>
MySQL5.6优化了Order by排序limit
查看>>
Gartner公司警告,由于企业削减投入,大数据泡沫或破裂
查看>>
TCP/IP协议栈中,为什么选择IP层负责分片?
查看>>
不治已病治未病
查看>>
【VMCloud云平台】SCDPM(二)部署
查看>>
聚云势,领变革--CISCO PLUS参会分享
查看>>
体验式培训之“盲人与哑巴”
查看>>
Windows Server 2012 R2工作文件夹⑩:排错
查看>>
Exchange工具01—使用Exchange EDB Viewer查看EDB文件
查看>>
《大数据产业发展规划》(2016-2020年)安全相关内容摘录
查看>>
VMware Workstation 8正式版试用之Team功能
查看>>