线程与 IO 模型
{Back to Index}  

Table of Contents

1 EventLoop

EventLoop 本质是一个单线程执行器,内部维护一个 Selector 对象,通过 run 方法处理 Channel 上源源不断的 IO 事件。

EventLoopGroup 则是一组 EventLoop 的集合,Channel 会通过 EventLoopGroup::register 绑定至其中一个 EventLoop ,后续所有关于此 Channel 的 IO 事件都由该 EventLoop 负责处理, 这样保证了 IO 处理的线程安全性。

常见的 EventLoopGroup 实现有:

NioEventLoopGroup
处理 IO 事件,普通任务,定时任务
DefaultEventLoopGroup
仅处理普通任务与定时任务

2 Channel/Unsafe

channels.png

Figure 1: Channel 类继承关系

Netty 中的 IO 操作最终都是在 channel pipeline 中由 Unsafe 完成的,pipeline 与 channel 和 usafe 的关系是一对一的,即 pipeline 中包含 channel 引用,channel 中初始化 unsafe 。

3 Future/Promise

io.netty.concurrent.Future 继承自 java.util.concurrent.Futureio.netty.util.concurrent.Promise 又对 io.netty.concurrent.Future 进行了扩展:

  • java.util.concurrent.Future

    只能同步等待任务结束才能得到结果。

  • io.netty.concurrent.Future

    可以同步等待任务结束从而得到结果【sync()】,也可以异步方式得到结果【addListerner()】,两者都是要以任务结束为前提。Future 一般是由框架代码生成并返回给应用程序使用的。

  • io.netty.util.concurrent.Promise

    可以当做 io.netty.concurrent.Future 使用,也可以作为通用的异步对象使用(即支持主动设置结果),即作为线程间传递结果的载体。 应用程序可以先创建 Promise 对象,再将其交给执行线程(或框架代码)处理。

4 Reactor 线程模型

event.png

Figure 2: 宏观模型

event-loop.png

Figure 3: Reactor 大致流程

NIOEventLoopGroup.png

Figure 4: 线程模型

  • event loop group 负责给每个 channel 分配 其需要注册的 event loop
  • executor 用于创建 一个 内部执行 IO 轮询的线程,线程对象保存在 thread 变量中
  • 所有的即时 task 存放在 MPSC 队列中,调度与延时 task 存放在 PQ 中
  • 每个 NioEventLoop 代表一个 Reactor 模型
NioEventLoop 初始化过程源码参考
IO 轮询逻辑源码参考

5 IO 模型

5.1 selector

selector.png

Figure 5: Selector 对象内存使用与 select() 原理

5.2 服务器处理流程

startup.png

Figure 6: 为了简化逻辑,中间函数调用过程有所忽略,但描述了大致的处理流程

NioSocketChannel 通常只关心 OP_READ 事件,但是如果在写操作时发现暂时无法写入,则会添加 OP_WRITE 感兴趣事件,这样当 selector 轮询到该事件时,说明系统缓冲区空出来了,可以写入了。

NioSocketChannel 创建步骤源码参考

Author: Hao Ruan (ruanhao1116@gmail.com)

Created: 2020-05-06 Wed 14:46

Updated: 2022-06-14 Tue 15:19

Emacs 27.2 (Org mode 9.4.4)