写点什么

netty 系列之:EventLoop,EventLoopGroup 和 netty 的默认实现

作者:程序那些事
  • 2022 年 2 月 23 日
  • 本文字数:2677 字

    阅读完需:约 9 分钟

netty系列之:EventLoop,EventLoopGroup和netty的默认实现

简介

在 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/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 刚刚阅读数: 2
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
netty系列之:EventLoop,EventLoopGroup和netty的默认实现