Netty学习--EventLoop和线程模型
2019-01-19 本文已影响58人
何何与呵呵呵
EventLoop 接口
EventLoop 的类层次结构
在这个模型中,一个EventLoop 将由一个永远都不会改变的Thread 驱动,同时任务(Runnable 或者Callable)可以直接提交给EventLoop 实现,以立即执行或者调度执行。根据配置和可用核心的不同,可能会创建多个EventLoop 实例用以优化资源的使用,并且单个EventLoop 可能会被指派用于服务多个Channel。
简单理解:一个EventLoop相当于一个循环,并有一条线程管理(Thread),当EventLoop添加或减少,线程也跟着改变.
-
Netty 4 中的I/O 和事件处理
所有的I/O操作和事件都由已经被分配给了EventLoop的那个Thread来处理. -
Netty 3 中的I/O 操作
所有的出站(下游)事件都由调用线程处理,其可能是I/O 线程也可能是别的线程。
问题一:多个出站事件同意调用一个ChannelHandle,因此需要在ChannelHandler 中对出站事件进行仔细的同步.
问题二:当Channel.write()方法导致异常时,需要生成并触发一个exceptionCaught 事件。但是在Netty 3 的模型中,由于这是一个入站事件,需要在调用线程中执行代码,然后将事件移交给I/O 线程去执行,然而这将带来额外的上下文切换。
任务调度
- 使用EventLoop 调度任务
Channel ch = ...
ScheduledFuture<?> future = ch.eventLoop().schedule( // 调度任务在从现在开始的60 秒之后执行
new Runnable() {
@Override
public void run() {
System.out.println("60 seconds later");
}
}, 60, TimeUnit.SECONDS);
实现细节
- 线程管理
EventLoop 的执行逻辑
永远不要将一个长时间运行的任务放入到执行队列中,因为它将阻塞需要在同一线程上执行的任何其他任务。如果必须要进行阻塞调用或者执行长时间运行的任务,我们建议使用一个专门的EventExecutor。
理解:一般EventLoop利用inEventLoop(Thread)绑定一条线程,如果需要多线程处理,则使用EventExecutor.
-
EventLoop/线程的分配
1.异步传输
用于非阻塞传输(如NIO 和AIO)的EventLoop 分配方式
在当前实现中,使用顺序循环(round-robin)的方式进行分配以获取一个均衡的分布,并且相同的EventLoop可能会被分配给多个Channel。
对于所有相关联的Channel 来说,ThreadLocal 都将是一样的。(同一个线程)
2.阻塞传输
阻塞传输(如OIO)的EventLoop 分配方式