【Netty】EventLoop和线程模型
一、前言
在学习了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和线程模型的更多相关文章
- Netty学习摘记 —— 再谈EventLoop 和线程模型
本文参考 本篇文章是对<Netty In Action>一书第七章"EventLoop和线程模型"的学习摘记,主要内容为线程模型的概述.事件循环的概念和实现.任务调度和 ...
- Netty实战七之EventLoop和线程模型
简单地说,线程模型指定了操作系统.编程语言.框架或者应用程序的上下文中的线程管理的关键方面.Netty的线程模型强大但又易用,并且和Netty的一贯宗旨一样,旨在简化你的应用程序代码,同时最大限度地提 ...
- Netty中的EventLoop和线程模型
一.前言 在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型. 二.EventLoop和线程模型 2.1. 线程模型 线 ...
- Netty 框架学习 —— EventLoop 和线程模型
EventLoop 接口 Netty 是基于 Java NIO 的,因此 Channel 也有其生命周期,处理一个连接在其生命周期内发生的事件是所有网络框架的基本功能.通常来说,我们使用一个线程来处理 ...
- Netty(二) 从线程模型的角度看 Netty 为什么是高性能的?
前言 在之前的 SpringBoot 整合长连接心跳机制 一文中认识了 Netty. 但其实只是能用,为什么要用 Netty?它有哪些优势?这些其实都不清楚. 本文就来从历史源头说道说道. 传统 IO ...
- 3 - EventLoop和线程模型-事件循环
a). EventLoopGroup为每个新创建的channel分配一个EventLoop,多个channel对应一个EventLoop. b). 一个EventLoop由一个不变的thread驱动, ...
- Netty源码死磕一(netty线程模型及EventLoop机制)
引言 好久没有写博客了,近期准备把Netty源码啃一遍.在这之前本想直接看源码,但是看到后面发现其实效率不高, 有些概念还是有必要回头再细啃的,特别是其线程模型以及EventLoop的概念. 当然在开 ...
- Reactor三种线程模型与Netty线程模型
文中所讲基本都是以非阻塞IO.异步IO为基础.对于阻塞式IO,下面的编程模型几乎都不适用 Reactor三种线程模型 单线程模型 单个线程以非阻塞IO或事件IO处理所有IO事件,包括连接.读.写.异常 ...
- 从线程模型的角度看Netty的高性能
转载:Netty(二) 从线程模型的角度看 Netty 为什么是高性能的? 传统 IO 在 Netty 以及 NIO 出现之前,我们写 IO 应用其实用的都是用 java.io.* 下所提供的包. 比 ...
随机推荐
- ArcGIS API for JavaScript 4.2学习笔记[30] 点和线高程查询(第八章完结)
终于到最后一篇了,可喜可贺. 本例先说明了如何进行单点的高程差分析,然后说明了道路的起伏分析.前者很直观地比较了两个年份的高程数据之间的差值,体现山区的高程变化(有啥用啊?)后者,一条路上的起点终点起 ...
- ArcGIS API for JavaScript 4.2学习笔记[27] 网络分析之最短路径分析【RouteTask类】
要说网页端最经典的GIS应用,非网络分析莫属了. 什么?你没用过?百度高德谷歌地图的路线分析就是活生生的例子啊!只不过它们是根据大实际背景优化了结果显示而已. 这个例子使用RouteTask进行网络分 ...
- SEO -- WordPress怎设置百度站长链接自动提交
百度站长平站更新了主动推送(实时)推送的方式,受到了广大站长的好评,但是对于使用WordPress的网站来说怎么设置自动提交呢,在这里介绍一种比较简单且有效的方法.我们可以使用 WP BaiDu Su ...
- Intellij Idea 用Maven 创建Hibernate 项目
第一步:创建maven项目 2. 3. 4.第三步保存之后进行下一步 到此点击finish maven项目创建成功,点击完成后会进行一系列jar包的下载 maven 仓库的默认存储位置 第二步:连接数 ...
- 跟着刚哥梳理java知识点——运算符(五)
运算符:是一种特殊的符号,用以表示数据的运算.赋值和比较. 1.算数运算符(+.-.*./.%.++.--) a)除: int i = 12; double d1 = i / 5; //2.0 dou ...
- okHttp基础用法
获取okHttp..jar.包 1.联网获取jar包 2.本地添加 okHttp的使用 get请求 1.创建okHttpClient对象new OkHttpClient(); 2.创建一个请求对象Re ...
- webpack 打包成功,但是css不起作用
问题: webpack 打包成功,但是css不起作用 问题分析/解决: 原因有以下几种 使用了webpack2的语法规则不正确; webpack2要求必须写-loader; 可能是只写了css-loa ...
- UEditor使用------图片上传与springMVC集成 完整实例
UEditor是一个很强大的在线编辑软件 ,首先讲一下 基本的配置使用 ,如果已经会的同学可以直接跳过此节 ,今天篇文章重点说图片上传; 一 富文本的初始化使用: 1 首先将UEditor从官网下载 ...
- Javascript使用克隆的原型模式
ECMAScript 5中提供了Object.create()方法. 使用这个方法很容易克隆一个一模一样的对象. var animal=function(){ this.blood=100; this ...
- 需求收集实例三之 FM
暂且叫这个项目叫FM.FM项目采用敏捷模式,需求的表现形式是Story. 此项目需求收集过程如下: 亮点:在公司第一次实践敏捷.用Story 而非 需求说明文档呈现需求. 败笔:没有处理好Story ...