1 NioEventLoop概述
总述
2 NioEventLoop创建概述
对应
对应
对应
对应
3 ThreadPerTaskThread
2 服务端Channel的创建
bind 对应样例的
跟进调试
通过反射创建的 channel
看看 channelFactory
反射创建服务端 Channel
首先
创建完毕了
ANC
4 创建NioEventLoop线程
5 创建线程选择器
先看看普通的
再看幂2的
循环取数组索引下标,& 比取模性能更高
6 NioEventLoop的启动
对应是
对应是
7 NioEventLoop执行概述
8 检测IO事件
对应的源码为
对应的源码为
执行至此,说明已进行了一次阻塞式的 select 操作
产生空轮询的判断
当空轮询次数大于阈值
阈值定义
阈值
避免空轮询的再次发生
创建新选择器
获取旧选择器的所有 key 值
netty 包装的 channel
将之前的 key 事件解除,并绑定新的选择器和对应的事件
更新选择器的 key
至此,解决了空轮bug
9 处理IO事件
原生JDK创建一个 selector
单线程处理,其实不需要两个数组,后续版本已经是一个数组
只需关注
根本不需要此三个方法
通过反射
即此类
继续反射流程
替换为优化后的 set 集合
一句话总结:用数组替换HashSet 的实现,做到 add 时间复杂度为O(1)
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线程任务的执行
定时任务
从定时任务中拉取
根据时间,时间相同根据名称
取nanotime 截止时间前的定时任务
从普通 taskqueue 中取任务
作者:芥末无疆sss
链接:https://www.jianshu.com/p/dd9afddaec08
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
共同學習,寫下你的評論
評論加載中...
作者其他優質文章