简介
在 netty 中不论是服务器端的 ServerBootstrap 还是客户端的 Bootstrap,在创立的时候都须要在 group 办法中传入一个 EventLoopGroup 参数,用来解决所有的 ServerChannel 和 Channel 中所有的 IO 操作和 event。
可能有的小伙伴还略微看了一下 netty 的源码,可能会发现还有一个和 EventLoopGroup 十分相似的类叫做 EventLoop。那么 EventLoopGroup 和 EventLoop 有什么关系呢?他们的底层和 channel 的交互关系是怎么样的呢?一起来看看吧。
EventLoopGroup 和 EventLoop
EventLoopGroup 继承自 EventExecutorGroup:
public interface EventLoopGroup extends EventExecutorGroup
在后面的文章中咱们讲过,EventExecutorGroup 中有一个 next 办法能够返回对应的 EventExecutor,这个办法在 EventLoopGroup 中进行了重写:
EventLoop next();
next 办法返回的不再是一个 EventExecutor,而是一个 EventLoop。
事实上,EventLoop 和 EventLoopGroup 的关系与 EventExecutor 和 EventExecutorGroup 的关系有些相似,EventLoop 也是继承自 EventLoopGroup,EventLoopGroup 是 EventLoop 的汇合。
public interface EventLoop extends OrderedEventExecutor, EventLoopGroup
在 EventLoopGroup 中,除了重写的 next 办法之外,还增加了 channel 的注册办法 register, 用于将 channel 和注册到 EventLoop 中,从而实现 channel 和 EventLoop 的绑定。
ChannelFuture register(Channel channel);
在 EventLoop 中,自多增加了一个 parent 办法,用来示意 EventLoop 和 EventLoopGroup 的关联关系:
EventLoopGroup parent();
EventLoopGroup 在 netty 中的默认实现
EventLoopGroup 在 netty 中的默认实现叫做 DefaultEventLoopGroup,先来看一下它的继承关系:
<img src=”https://img-blog.csdnimg.cn/119283e9b8d04854940abc0fc159c604.png” style=”zoom:67%;” />
如果看了之前我解说的对于 EventExecutorGroup 的敌人能够看进去,DefaultEventLoopGroup 和 DefaultEventExecutorGroup 的继承关系是很相似的,DefaultEventLoopGroup 继承自 MultithreadEventLoopGroup, 而 MultithreadEventLoopGroup 又继承自 MultithreadEventExecutorGroup 并且实现了 EventLoopGroup 接口:
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup
MultithreadEventLoopGroup 是用多线程来解决 Event Loop。
在 MultithreadEventLoopGroup 中定义了一个 DEFAULT_EVENT_LOOP_THREADS 来存储默认的解决 Event Loop 线程的个数:
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
对于 EventLoopGroup 中新加的几个 register 办法,MultithreadEventLoopGroup 都是调用对应的 next 办法来实现的:
public ChannelFuture register(Channel channel) {return next().register(channel);
}
这里的 next() 办法的实现实际上调用的是父类的 next 办法,也就是 MultithreadEventExecutorGroup 中的 next 办法,来抉择 Group 治理的一个 EventLoop:
public EventLoop next() {return (EventLoop) super.next();}
对于 DefaultEventLoopGroup 来说,它继承自 MultithreadEventLoopGroup,实现了一个 newChild 办法,用来将传入的 executor 封装成为 EventLoop:
protected EventLoop newChild(Executor executor, Object... args) throws Exception {return new DefaultEventLoop(this, executor);
}
EventLoop 在 netty 中的默认实现
EventLoop 在 netty 中的默认实现叫做 DefaultEventLoop,先来看下它的继承关系:
<img src=”https://img-blog.csdnimg.cn/9c642b58f6c248f9bddfbb71799549f9.png” style=”zoom:67%;” />
DefaultEventLoop 继承自 SingleThreadEventLoop, 而 SingleThreadEventLoop 又继承自 SingleThreadEventExecutor 并且实现了 EventLoop 接口。
先来看下 SingleThreadEventLoop 的实现:
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop
SingleThreadEventLoop 应用繁多线程来执行提交的工作。它和 SingleThreadEventExecutor 相比有什么变动呢?
首先 提供了一个 tailTasks 用来存储 pending 的 tasks:
private final Queue<Runnable> tailTasks;
这个 tailTasks 会被用在工作个数的判断和操作上:
final boolean removeAfterEventLoopIterationTask(Runnable task) {return tailTasks.remove(ObjectUtil.checkNotNull(task, "task"));
}
protected boolean hasTasks() {return super.hasTasks() || !tailTasks.isEmpty();}
public int pendingTasks() {return super.pendingTasks() + tailTasks.size();}
SingleThreadEventLoop 中对 register 办法的实现最终调用的是注册的 channel 中 unsafe 的 register 办法:
channel.unsafe().register(this, promise);
再来看一下 DefaultEventLoop,DefaultEventLoop 继承自 SingleThreadEventLoop:
public class DefaultEventLoop extends SingleThreadEventLoop
除了构造函数之外,DefaultEventLoop 实现了一个 run 办法, 用来具体任务的执行逻辑:
protected void run() {for (;;) {Runnable task = takeTask();
if (task != null) {task.run();
updateLastExecutionTime();}
if (confirmShutdown()) {break;}
}
}
如果比照能够发现,DefaultEventLoop 和 DefaultEventExecutor 中 run 办法的实现是一样的。
总结
本文介绍了 netty 中 EventLoop 和 EventLoopGroup 的默认实现:DefaultEventLoop 和 DefaultEventLoopGroup,然而不晓得小伙伴们有没有发现,即便在最简略的 netty 利用中也很少看到这两个默认的 EventLoop。最罕用的反而是 NioEventLoopGroup 和 NioEventLoop,这是因为 DefaultEventLoop 和 DefaultEventLoopGroup 只是应用了多线程技术,一个线程代表一个 EventLoop,在 EventLoop 过多的状况下可能会造成线程和性能的节约,所以在 NioEventLoopGroup 和 NioEventLoop 应用了 NIO 技术,通过应用 channel、selector 等 NIO 技术晋升了 EventLoop 的效率。对于 NioEventLoopGroup 和 NioEventLoop 的具体介绍,咱们会在后一章中具体解说,敬请期待。
本文已收录于 http://www.flydean.com/05-1-netty-eventloop-eventloopgroup/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!