Netty 学习 - EventLoop

原创 2016年12月24日 16:22:34
     上一篇文章记录了服务端和客户端的启动流程,本文介绍一下类关系以及eventLoop等知识,本研究主要还是以NIO为主
   




                                                                                                    AbstractNioByteChannel     -    NioSocketChannel
Channel  -  AbstractChannel  -  AbstractNioChannel - 
                                                                                                    AbstactNioMessageChannel  -  NioServerSocketChannel








                                                                                                                                                                                       
Unsafe(Channel) -  AbstractUnsafe(AbstractChannel) -  AbstractNioUnsafe(AbstractNioChannel ) 
                                                                                          
                                                                                      
             NioByteUnsafe(AbstractNioByteChannel)     -        NioSocketChannelUnsafe(NioSocketChannel)                                         
                                                                                     
  --
             NioMessageUnsafe( AbstactNioMessageChannel )




                                                                                                                                                                            
Unsafe是Channle的内部接口,这么定义的目的是为了独立出unsafe的功能,unsafe是用于真正通信的组件,而unsafe又应该只被channel调用,而不应该被其他模块可见




再看一下ServerBootStrap中的两个group的含义以及目的,第一个group可以称为bossGroup,第二个group可以称为workerGroup,在Server启动后,bossGroup中一个eventLoop会启动进行轮询, NioServerSocketChannel在这个eventLoop的selector上注册了Accept事件,当有客户端连接上来后,会触发selectKey,
在eventLoop中处理selectKey的代码中
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;
                }
            }








执行到  NioMessageUnsafe的read方法,执行到NioServerSocketChannel的doReadMessages方法
 @Override
    protected int doReadMessages(List<Object> buf) throws Exception {
        SocketChannel ch = javaChannel().accept();




        try {
            if (ch != null) {
                buf.add(new NioSocketChannel(this, ch));
                return 1;
            }
        } catch (Throwable t) {
            logger.warn("Failed to create a new channel from an accepted socket.", t);




            try {
                ch.close();
            } catch (Throwable t2) {
                logger.warn("Failed to close a socket.", t2);
            }
        }




        return 0;
    }








  
此时一个新的连接在服务端就会有一个新的NioSocketChannel对象,到这里为止,只是对象建立了,后续还有对象的pipeline,handler等等需要构建




在  NioMessageUnsafe完成  doReadMessages方法后,会触发 pipeline.fireChannelRead(readBuf.get(i)),由于这个pipeline是NioServerSocketChannel的pipeline
readBuf.get(i)的值就是前面新建的NioSocketChannel对象,根据handler链调用到前面一章介绍到的 ServerBootstrapAcceptor,执行到channelRead方法,该方法包括两个主要工作
1    child.pipeline().addLast(childHandler);    该步骤会将应用程序预先设置的的handler加到该NioSocketChannel的pipeline中                                                                                    
                                                                                    
2    childGroup.register(child) ,其中childGroup就是用户设置的workGroup




从上面的解释可以很清楚的看到,处理客户端连接的是bossGroup,而新建NioSocketChannel对象后,这个对象会用workerGroup进行连接处理等




再来看看EventLoop,还是以NioEventLoop为例来介绍,NioEventLoop需要处理网络I/O读写事件,还需要执行系统任务和定时任务


在Netty的很多代码中,都会有如下实现方式:


if (eventLoop.inEventLoop()) {
                register0(promise);
            } else {
                try {
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            register0(promise);
                        }
                    });


首先会判断当前执行线程是否是eventLoop线程,如果不是会通过eventLoop的execute方法进行异步执行,再来看看execute方法


execute方法在SingleThreadEventExecutor
public void execute(Runnable task) {
        if (task == null) {
            throw new NullPointerException("task");
        }


        boolean inEventLoop = inEventLoop();
        if (inEventLoop) {
            addTask(task);
        } else {
            startThread();
            addTask(task);
            if (isShutdown() && removeTask(task)) {
                reject();
            }
        }


如果当前线程是eventLoop线程,则直接放到task队列中,如果不是,则尝试开始启动eventLoop线程并在内部缓存进行记录线程启动状态后放入task队列


eventLoop中有for的循环体,用来处理selectkey事件,eventLoop处理IO和系统任务的比例有ioRadio控制,eventLoop会保证先处理完IO事件,完成IO事件后,会根据IO事件的事件和配置的比例算出对应执行系统任务的时间,开始执行系统任务,执行64个任务后,比较任务总执行时间是否超过配置的时间,再进行对应的处理
 
 // Check timeout every 64 tasks because nanoTime() is relatively expensive.
            // XXX: Hard-coded value - will make it configurable if it is really a problem.
            if ((runTasks & 0x3F) == 0) {
                lastExecutionTime = ScheduledFutureTask.nanoTime();
                if (lastExecutionTime >= deadline) {
                    break;
                }




最后来看看EventLoopGroup的关闭方法,shudownGraceFully的基本逻辑如下:
每个eventLoop中的都有内部变量STATE_UPDATE用来维护该eventLoop的状态,当执行shutdownGraceFully方法时,会将状态设置为shutdown,在这个步骤中仅仅是设置状态即可
在eventLoop的轮询中,完成IO轮询和任务调度后,会执行以下操作
 
 
if (isShuttingDown()) {
                    closeAll();
                    if (confirmShutdown()) {
                        break;
                    }
                }






 其中if的判断就是会去检查状态,如果是shutdown,则会执行closeAll,注意是group执行的shutodown,所以group中管理的所有eventLoop均会轮询到closeAll方法中


closeAll会循环eventLoop上的多路复用器selector上绑定的所有channel,通过channel的unsafe依次关闭channel,释放线程池,完成关闭操作


如果是用户调用的channel.close则会封装为用户任务,在eventLoop的轮询中进行处理




对于任何架构,线程模型设计的好坏都直接影响软件的性能和并发处理能力


                    

相关文章推荐

Netty 框架总结「ChannelHandler 及 EventLoop」

学习了一段时间的 Netty,将重点与学习心得总结如下,本文主要总结ChannelHandler 及 EventLoop 的知识点和基本用法,本文章节排序参照《Netty in Action》的章节排...

Netty线程模型及EventLoop和EventLoopGroup源码解析

1、netty线程模型
  • zxh87
  • zxh87
  • 2017年06月19日 15:29
  • 322

Netty in Action (十七) 第七章节 EventLoop和线程模型

本章节包括: 1)线程模型总览 2)Event Loop概念和具体实现 3)任务调度 4)实现细节 简单地陈述一下,对于一个操作系统,编程语言,框架,或者应用来说,线程模型对其都是至关重要的一...
  • linuu
  • linuu
  • 2016年04月24日 11:43
  • 3675

java游戏服务器之网络层Netty 之EventLoop

java游戏服务器网络层越来越流行netty,毕竟版本更新快,支持新的特性,更多的功能支持。相比下来mina慢了好多。现在就开始分析下对应的代码吧。估计这段时间要花的时间有点长...

Netty 源码分析之 EventLoop(二) (最重要)

目录 Netty 的 IO 处理循环 thread 的 run 循环 IO 事件的轮询 IO 事件的处理 Netty 的任务队列机制 Task 的添加 任务的执行 Netty 的 IO 处理...
  • jeffleo
  • jeffleo
  • 2017年04月05日 14:16
  • 473

Netty In Action中文版 - 第十六章:从EventLoop取消注册和重新注册

本章介绍
  • abc_key
  • abc_key
  • 2014年08月11日 14:25
  • 3238

Netty源码分析之EventLoop相关结构分析

先来一个继承图,仅仅观察EventExecutor体系的轮廓 EventLoop > image2015-8-31 19:50:43.png" height="400" src="http://w...

Netty之基于EventLoop机制的高效线程模型

**引言** 对于RPC应用高性能的三个主题永远是IO模型、数据协议、线程模型。目前Netty提供的高效线程模型为线程模型提供了一种很好的解决思路。本文针对Netty线程模型的设计进行分析,并对IO...

[netty源码分析]--EventLoopGroup与EventLoop 分析netty的线程模型

netty核心类源码解析:分析netty的运行机制 EventLoopGroup与EventLoop解析:分析netty的线程模型 这一篇博文主要是从源码层次分析netty的线程...

muduo网络库学习之EventLoop(四):EventLoopThread 类、EventLoopThreadPool 类

1、Socket 操作封装 Endian.h 封装了字节序转换函数(全局函数,位于muduo::net::sockets名称空间中)。 SocketsOps.h/ SocketsOps.cc ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Netty 学习 - EventLoop
举报原因:
原因补充:

(最多只允许输入30个字)