美文网首页
Netty学习之EventLoop&Threading

Netty学习之EventLoop&Threading

作者: 颜洛滨 | 来源:发表于2018-10-11 15:27 被阅读5次

    Netty学习之EventLoop&Threading Model

    前言

    在前面我们学习了Netty的众多组件,如ByteBuf、Channel、ChannelHandler、ChannelPipeline等,这些组件组合起来具有神奇的魔力,而EventLoop则是赋予它们魔力的源泉,EventLoop是Netty的线程模型,也是Netty的心脏,本小节我们就来学习EventLoop相关的内容。

    EventLoop

    事件循环Event Loop:在连接的生命周期中,通过运行任务来处理事件(其实就是循环扫描事件列表,然后根据出现的事件来进行处理,单词Event Loop),EventLoop的基本原理如下

    while(!terminated) {
        // 等待事件的到来
        List<Runnable> readyEvents = blockUtilEventsReady();
        // 如果有事件,则进行处理
        for(Runnable ev: readyEvents) {
            ev.run();
        }
    }
    

    在Netty的模型中,一个EventLoop对应一个线程,然后任务能够直接提交到EventLoop的实现去直接或者参与调度,根据CPU核的数量,可能同时有多个EventLoop创建出来用于提高性能的资源利用率,单一的一个EventLoop能够服务多个Channels

    这里需要注意的是,一个Channel只会跟一个EventLoop绑定,但是一个EventLoop可以服务于多个Channels,所以并不是一对一的关系,这也是Netty能够减少线程使用数量,从而提高资源利用率的原因之一。

    Netty中的EventLoop继承于ScheduledExecutorService,并且定义了一个parent()方法,通过该方法可以获得当前EventLoop实现实例所归属的EventLoopGroup实例

    Netty中的任务以及事件是以FIFO的顺序执行,这样可以保证数据流能够以正确的顺序进行处理。

    一个Event的类型通常决定了其会被如何处理,如传输数据到用户层、处理数据等,为了使得事件处理逻辑更通用以及灵活,Netty4中所有的I/O操作以及事件被EventLoop所属的线程处理,其具体实现是判断当前触发I/O操作的线程是否是当前channel所对应的EventLoop所对应的线程,如果是的话,则执行该任务,如果不是的话,则将其放入对应的队列中,等待稍后对应的线程来执行,从而保证了一个channel中的事件都是由同一个线程来处理,减少了同步锁所带来的开销,这也是前面提到的,Channel是线程安全的,可以被其他线程所操作的原因,EventLoop执行逻辑如下图所示(图片来自《Netty in action》,下同)。

    EventLoop执行逻辑

    任务调度

    在JDK中,可以通过单线程的Timer类以及线程池对象ScheduledExecutorService来执行,但该方式在负载比较重的情况下,会出现性能问题,额外的线程用于维护线程池,当多个线程同时调度时,会出现瓶颈。

    在Netty中,通过使用EventLoop来实现调度功能

    Channel ch = ...;
    
    ScheduledFuture<?> future = ch.eventLoop().schedule(
        new Runnable() {
            // ops
        }, 60, TimeUnit.SECONDS);
    

    EventLoop分配

    EventLoop从EventLoopGroup中申请,EventLoopGroup可以理解为EventLoop的容器(类似于线程跟线程池的关系),可以根据需要从EventLoopGroup获取EventLoop(及其绑定的线程)。

    异步的实现使用少量的EventLoops,并且可能在多个Channel中共享,这种方式允许少量的线程来服务多个Channel,而不是每个Channel分配一个线程,一旦一个Channel被赋予一个EventLoop,在其生命周期中就只会使用该EventLoop及其绑定的线程,所以在同一个Channel中,不需要过多担心线程安全问题(只有一个线程嘛)。

    EventLoopGroup、EventLoop、Channel之间的关系如下图所示(非阻塞模式,即NIO、AIO)

    NIO、AIO中EventLoop模型

    阻塞实现,对于传统的OIO,由于会发生阻塞,所以不能复用EventLoop(一个EventLoop对应一个线程),Netty采用的是每个EventLoop对应一个Channel

    OIO中EventLoop模型

    总结

    本小节我们学习了Netty的EventLoop及相关内容,包括EventLoop与线程、Channel的关系,EventLoop与EventLoopGroup的关系等,由于Netty中的Channel与唯一的EventLoop绑定,而EventLoop与唯一的线程绑定,所以,在使用的时候需要注意,不能在一个EventLoop中执行阻塞操作,否则会影响其他Channel的处理,与此同时,由于EventLoop的设计,Channel是线程安全的,可以在多线程环境中使用。

    相关文章

      网友评论

          本文标题:Netty学习之EventLoop&Threading

          本文链接:https://www.haomeiwen.com/subject/rqmbaftx.html