一、前言

  在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型。

二、EventLoop和线程模型

  2.1. 线程模型

  线程池可通过缓存和复用已有线程来提高系统性能,基本的缓冲池模式可描述如下:

    · 从池中空闲链表中选取线程,然后将其分配赋予给已提交的任务。

    · 当线程完成工作时,该线程又返回至空闲链表,可再进行复用。

  该模式如下图所示。

  

  池化和复用线程是针对每个任务都需要创建和销毁线程的改进,但还是需要进行上下文切换,并且随着线程数量的增加,其负担也会增加。同时,在高并发下也会出现很多线程问题。

  2.2. EventLoop接口

  任何网络框架的基本功能都是运行任务来处理在连接声明周期中所发生的事件,相应的编程结构通常被称为事件循环。事件循环的基本思想如下代码所示,每个任务都是一个Runnable实例。  

while (!terminated) {
List<Runnable> readyEvents = blockUntilEventsReady();
for (Runnable ev: readyEvents) {
ev.run();
}
}

  Netty的EventLoop是使用concurrency和networking两个基本API的协作设计的一部分,Netty中的io.netty.util.concurrent 包基于JDK的java.util.concurrent包进行设计。另外,io.netty.channel包中的类也继承它们,以便与其事件相关联,具体继承关系如下图所示。

  

  在这个模型中,EventLoop由一个永不改变的线程驱动,任务(Runnable或Callable)可以直接提交给EventLoop的实现,以便立即执行或有计划地执行。根据配置和可用内核,可以创建多个EventLoops以优化资源使用,并且可以为单个EventLoop分配服务多个通道。

  事件和任务以FIFO的方式被执行,这通过保证以正确的顺序处理字节内容来消除数据损坏的可能性。

  1. Netty 4中的I/O和事件处理

  由I/O操作触发的事件流过具有一个或多个ChannelHandler的ChannelPipeline时,传播这些事件的方法调用可以由ChannelHandler拦截,并根据需要进行处理,根据事件的不同,需要进行不同的处理,但事件处理逻辑必须具有通用性和灵活性,以处理所有可能的用例,因此,在Netty 4中,所有的I/O操作和事件都由已分配给EventLoop的线程处理。

  2. Netty 3中的I/O处理

  以前版本中使用的线程模型仅保证入站(上游)事件将在所谓的I/O线程中执行,所有出站(下游)事件由调用线程处理,其需要在ChannelHandlers中仔细同步出站事件,因为不可能保证多个线程不会同时尝试访问出站事件。

  2.3 任务调度

  有时需要让一个任务稍后(延迟)或定期执行,一个常见的用例是向远程对等体发送心跳消息,以检查连接是否仍然存在。

  1. JDK调度API

  在Java 5之前,任务调度基于java.util.Timer构建,其使用后台线程,与标准线程具有相同的限制,随后,Java提供了ScheduledExecutorService接口,如下代码在60S后执行任务。  

ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
ScheduledFuture<?> future = executor.schedule(
new Runnable() {
@Override
public void run() {
System.out.println("60 seconds later");
}
}, 60, TimeUnit.SECONDS); executor.shutdown();

  2. 使用EventLoop调度任务

  ScheduledExecutorService实现有限制,如为管理池需要创建额外的线程,如果许多任务被调度,这可能会成为系统性能瓶颈。Netty通过使用Channel的EventLoop调度来解决这个问题,如下代码所示。  

Channel ch = ...
ScheduledFuture<?> future = ch.eventLoop().schedule(
new Runnable() {
@Override
public void run() {
System.out.println("60 seconds later");
}
}, 60, TimeUnit.SECONDS);

  60秒后,Runnable实例将由分配给该Channel的EventLoop执行。若想每隔60S执行任务,则需要做如下处理。  

Channel ch = ...
ScheduledFuture<?> future = ch.eventLoop().scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
System.out.println("Run every 60 seconds");
}
}, 60, 60, TimeUnit.Seconds);

  因为EventLoop继承ScheduledExecutorService,因此可以调用ScheduledExecutorService的所有方法。

  2.4 实现细节

  1. 线程管理

  Netty的线程模型的优越性能取决于确定当前正在执行的线程的身份,即是否为分配给当前Channel及其EventLoop的线程。如果调用的是EventLoop的线程,那么直接执行该代码块,否则,EventLoop调度一个任务以供稍后执行,并将其放入内部队列中,当处理下个事件时,会处理队列中的事件,这解释了任何线程为何可以直接与Channel交互,而不需要在ChannelHandler中同步。

  每个EventLoop都有自己的任务队列,与其他EventLoop独立,下图显示了EventLoop的执行逻辑。

  

  不要把长时间的任务放在执行队列中,因为它将阻止任何其他任务在同一个线程上执行。如果必须进行阻塞调用或执行长时间运行的任务,建议使用专用的EventExecutor。

  2. EventLoop/线程的分配

  为通道的I/O和事件提供服务的EventLoops包含在EventLoopGroup,EventLoops创建和分配的方式根据传输实现(异步和阻塞)而有所不同。

  · 异步传输。只使用少量的EventLoopGroup,在当前的模型中其在通道中共享。这允许通道由最小数量的线程提供服务,而不是为每个通道分配一个线程。下图展示了包含三个EventLoop(每个EventLoop由一个线程驱动)的EventLoopGroup,EventLoopGroup创建时会直接分配EventLoops(及其线程),以确保它们在需要时可用,EventLoopGroup负责将EventLoop分配给每个新创建的通道,当前的实现是使用循环方法实现均衡分配,相同的EventLoop可被分配给多个通道

  

  一旦一个Channel被分配了一个EventLoop,它将在其生命周期中一直使用这个EventLoop(和相关联的线程)。同时请注意EventLoop的分配对ThreadLocal影响,因为一个EventLoop通常驱动多个通道,多个通道的ThreadLocal也相同。

  · 阻塞传输。OIO的实现与异步传输的实现大不相同,其如下图所示。

  

  每个通道将会分配一个EventLoop(以及相关线程),Channel的IO事件将由独立的线程处理。

三、总结

  本篇博文讲解了EventLoop及其线程模型,以及其与通道之间的关系,EventLoopGroup可对应多个EventLoop,一个EventLoop对应一个线程,一个EventLoop可对应多个通道。也谢谢各位园友的观看~

【Netty】EventLoop和线程模型的更多相关文章

  1. Netty学习摘记 —— 再谈EventLoop 和线程模型

    本文参考 本篇文章是对<Netty In Action>一书第七章"EventLoop和线程模型"的学习摘记,主要内容为线程模型的概述.事件循环的概念和实现.任务调度和 ...

  2. Netty实战七之EventLoop和线程模型

    简单地说,线程模型指定了操作系统.编程语言.框架或者应用程序的上下文中的线程管理的关键方面.Netty的线程模型强大但又易用,并且和Netty的一贯宗旨一样,旨在简化你的应用程序代码,同时最大限度地提 ...

  3. Netty中的EventLoop和线程模型

    一.前言 在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型. 二.EventLoop和线程模型 2.1. 线程模型 线 ...

  4. Netty 框架学习 —— EventLoop 和线程模型

    EventLoop 接口 Netty 是基于 Java NIO 的,因此 Channel 也有其生命周期,处理一个连接在其生命周期内发生的事件是所有网络框架的基本功能.通常来说,我们使用一个线程来处理 ...

  5. Netty(二) 从线程模型的角度看 Netty 为什么是高性能的?

    前言 在之前的 SpringBoot 整合长连接心跳机制 一文中认识了 Netty. 但其实只是能用,为什么要用 Netty?它有哪些优势?这些其实都不清楚. 本文就来从历史源头说道说道. 传统 IO ...

  6. 3 - EventLoop和线程模型-事件循环

    a). EventLoopGroup为每个新创建的channel分配一个EventLoop,多个channel对应一个EventLoop. b). 一个EventLoop由一个不变的thread驱动, ...

  7. Netty源码死磕一(netty线程模型及EventLoop机制)

    引言 好久没有写博客了,近期准备把Netty源码啃一遍.在这之前本想直接看源码,但是看到后面发现其实效率不高, 有些概念还是有必要回头再细啃的,特别是其线程模型以及EventLoop的概念. 当然在开 ...

  8. Reactor三种线程模型与Netty线程模型

    文中所讲基本都是以非阻塞IO.异步IO为基础.对于阻塞式IO,下面的编程模型几乎都不适用 Reactor三种线程模型 单线程模型 单个线程以非阻塞IO或事件IO处理所有IO事件,包括连接.读.写.异常 ...

  9. 从线程模型的角度看Netty的高性能

    转载:Netty(二) 从线程模型的角度看 Netty 为什么是高性能的? 传统 IO 在 Netty 以及 NIO 出现之前,我们写 IO 应用其实用的都是用 java.io.* 下所提供的包. 比 ...

随机推荐

  1. WPF 截屏软件开发

    最近由于工程需要开始研发基于Windows的自动录屏软件,很多细节很多功能需要处理,毕竟一个完美的录屏软件不是你随随便便就可以写出来的.首先参考了大部分的录屏软件,在研发的过程中遇到了很多的问题:比如 ...

  2. PID控制算法研究

    1.matlab模糊控制工具箱:http://blog.csdn.net/gameboy12615/article/details/6367459 2.书籍:先进PID控制MATLAB仿真/刘金琨著 ...

  3. PLSQL创建定时任务

    在使用oracle最匹配的工具plsql的时候,如果用plsql创建定时器呢?下面我简单介绍使用工具创建定时器的方法: 1.创建任务执行的存储过程,如名称为YxtestJob,向测试表中插入数据 cr ...

  4. Xcode上传代码到github

    1.下载GitHub的Mac客户端 2.在Finder->下载,找到双击安装 3.打开Github Desktop软件, 需要进行登录, 登录的用户名密码就是github的用户信息,(如果没有去 ...

  5. 深入解析Hashtable、Dictionary、SortedDictionary、SortedList

    我们先看Hashtable. MSDN的解释:表示键/值对的集合,这些键/值对根据键的哈希代码进行组织. Hash算法是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定 ...

  6. StringBuilder的实现

    先看看MS给出的官方解释吧 (http://msdn.microsoft.com/zh-cn/library/system.text.stringbuilder(VS.80).aspx) String ...

  7. Java--向数据库添加txt文件中的批量数据

    大家可能会遇到这样的问题,在做一个项目时需要操作数据库,需要有大量的数据需要导入到数据库中,这部分数据存到了txt文档中(可以把Word文档中的数据弄到txt文档),总不能每一条数据都复制黏贴到数据库 ...

  8. python2与python3的不兼容_urllib2

    网页下载器:将URL对应的网页以HTML下载到本地,用于后续分析 常见网页下载器:Python官方基础模块:urllib2 第三方功能包:requests python 3.x中urllib库和uri ...

  9. poj3020二分图匹配

    The Global Aerial Research Centre has been allotted the task of building the fifth generation of mob ...

  10. 学习Spark——环境搭建(Mac版)

    大数据情结 还记得上次跳槽期间,与很多猎头都有聊过,其中有一个猎头告诉我,整个IT跳槽都比较频繁,但是相对来说,做大数据的比较"懒"一些,不太愿意动.后来在一篇文中中也证实了这一观 ...