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,先來看一下它的繼承關系:

如果看了之前我講解的關於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,先來看下它的繼承關系:

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/

最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM