zoukankan      html  css  js  c++  java
  • Netty源码分析--Channel注册(上)(五)

            其实在将这一节之前,我们来分析一个东西,方便下面的工作好开展。

            打开启动类,最开始的时候创建了一个NioEventLoopGroup 事件循环组,我们来跟一下这个。

            

          这里bossGroup, 我传入了一个线程, workerGroup 没有入参,默认0, 也就是说父级我用一个线程来处理客户端的接入, 多个线程来处理客户端的读写操作

          通过一连串的构造方法进入到

         executor 是 null , selectorProvider 用来创建一个多路复用器, 最后一个参数传入了 一个多路复用器的一个策略, 这个策略我们后面会讲到

        

         紧接着又传入了一个拒绝策略, 由于  NioEventLoopGroup 继承了 MultithreadEventLoopGroup,所以进入 MultithreadEventLoopGroup 的构造方法

         

        这里的判断, bossGroup 传入了 1 ,所以nThreads = 1;  workerGroup 没有入参,默认是0 ,所以这里到了一个判断默认线程数的地方。

       

         就是这了, NettyRuntime.availableProcessors() * 2  代表 CPU核心数 * 2(处理器超线程数) * 2的值  或  CPU数 * 2的值  

         在cmd命令中输入“wmic”,然后在出现的新窗口中输入“cpu get *”。
         NumberOfCores:表示CPU核心数
         NumberOfLogicalProcessors:表示CPU线程数

         

         所以我这里是 CPU核心数 是 2 , CPU 线程数 是 4 , 所以我的 NettyRuntime.availableProcessors() * 2 = 8, 然后这里Math.max(1,8) 取大的 就是 8 了

         所以我的 workerGroup 线程数 是 8

         好了,我们继续跟进去

        

         这里创建了一个线程工厂,主要是为线程设置名字、是否守护进程、线程的优先级等等。然后创建一个任务执行器,把线程工厂传进去赋给成员变量

         这个executor 后面在每个 事件执行器 创建子线程处理task来用

        接下来创建一个长度是nThreads的 EventExecutor[]  ,对于 子事件循环组来说,这里其实是创建了一个长度为8 的NioEventLoop的数组, 即 EventExecutor[]  children = new NioEventLoop[8]

        这个地方我纠结了一下,因为我语文太差了,我决定画个图来展示一下, 虽然我美术也不好。

        

        大家看下这个代码层级结构, 其实就很显而易见了,这里我要说一下,SingleThreadEventExecutor 中有一个thread成员变量,说明每个都只有一个线程来处理,并且含有任务队列和任务的执行器。

       另外每一个NioEventLoop都含有一个selector 多路复用器 。

       继续看,这里通过默认的选择工厂来创建一个选择器。

       

       跟进去,我们看到下面的这段代码,不得不感叹Netty真的已经把性能发挥到了极致,能用位运算的绝不会用数学计算法,所以这里对选择器进行了区分

      

       

        看这个判断方法,意思是 如果是 2的次方 ,那么创建一个 PowerOfTwoEventExecutorChooser 选择器

        我特意去验证了一个这个算法

        

       结果是:

        

       好了,讲到这里我们可以重新开始讲注册了,仍然进入  initAndRegister()方法

       

        config().group() 这个获取到的 是 ServerBootStrap.group(), 那么也就是取到了 父级的事件循环组 也就是bossGroup

     根据我上上图的分析,那么注册方法进入的肯定是 MultithreadEventLoopGroup 

       

      这里有一个next()方法,用来选择一个NioEventLoop。由于我这里是1个线程的数组,所以进入

      

      因此,对于bossGroup来说,就是 0 & 0 = 0   1 & 0 = 0  2 & 0 = 0 .....

                对于workerGroup来说,就是 0 & 7 = 0 1 & 7 = 1  2 & 7 = 2 .... 8 & 7 = 0  9 & 7 = 1 ....

     所以这里其实是一个轮询的算法。

     ok, 看到这里我们猜测是 从   new NioEventLoop[1]  中轮询一个 NioEventLoop, 然后把channel注册到上面的多路复用器上。

     继续看, 根据那个流程图,可以推断出是进入到  SingleThreadEventLoop

     

        接着传入了一个 DefaultChannelPromise ,用来做注册结果的异步通知的。传入了channel 和 当前的这个 SingleThreadEventLoop ,当然具体怎么异步通知的,我们后面会讲到

     

       继续看

      

      这里把刚刚选择出来的 NioEventLoop 赋给 Channel 的 eventLoop 的成员变量, 这里也就意味着 ,这个NioEventLoop 也将一直伴随 这个channel 的所有的读写操作, 因为通过上面的那个流程图表明了 一个NioEventLoop 上面只有一个Thread , 那么也可以得出 一个Channel 整个周期 内所有的读写操作,全部由同一个Thread来完成, 这也就说明了为什么Netty没有线程安全问题,当然随着后面的讲解,你将会对这个地方理解的更加的深刻。 

           好了,注册的内容我们下一节接着说。

  • 相关阅读:
    第一次离职
    代码人生
    Array.Sort()实现细节和效率
    步入正轨
    2013,冲刺、加油!!!
    Struts2 OGNL 字符串自定义转化对象细节
    Struts2 输入格式自动校验的一些注意事项
    MySQL 5.7.17 Windows安装和启动
    关于Hibernate 5 和 Hibernate 4 在创建SessionFactory的不同点分析(解决 org.hibernate.MappingException: Unknown entity: xx类报错问题)
    Struts2 OGNL 自动转换Date类型的一些注意事项
  • 原文地址:https://www.cnblogs.com/huxipeng/p/10994455.html
Copyright © 2011-2022 走看看