1. 程式人生 > >netty原始碼分析(十六)Channel選擇器工廠與輪詢演算法及註冊底層實現

netty原始碼分析(十六)Channel選擇器工廠與輪詢演算法及註冊底層實現

上一節說到註冊的入口,即
MultithreadEventLoopGroup:

    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }

註冊channel第一步呼叫了next()方法,next()是MultithreadEventLoopGroup裡邊的:

    public EventLoop next() {
        return (EventLoop) super.next();
    }

到了父類MultithreadEventExecutorGroup:

    public EventExecutor next() {
        return chooser.next();
    }

這裡出現了一個chooser:

private final EventExecutorChooserFactory.EventExecutorChooser chooser;

看一下他的結構,EventExecutorChooserFactory是一個工廠,生產各種Executor,,用EventExecutorChooserFactory的實現類DefaultEventExecutorChooserFactory看一下:

/**
 * Default implementation which uses simple round-robin to choose next {@link EventExecutor}.
 * 預設使用round-robin演算法選擇下一個例項的EventExecutor實現
 * round-robin:主要用在負載均衡方向,比如有5臺機器,第一次分請求到了第一臺機器,第二次到了第二臺機器,第三次請求到了第三臺請求,以此類推一直到第五臺機器,然後第六次又到了第一臺機器,這樣一個輪流的呼叫,處理負載,這裡的Executor陣列也是使用這種方式,保證數組裡邊的EventExecutor被均衡呼叫。
 */
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory { public EventExecutorChooser newChooser(EventExecutor[] executors) { if (isPowerOfTwo(executors.length)) { return new PowerOfTwoEventExecutorChooser(executors); } else { return
new GenericEventExecutorChooser(executors); } }

從這裡可以看到netty對效能的壓榨,當有2的指數個executor的時候使用PowerOfTwoEventExecutorChooser效能會比非指數個的GenericEventExecutorChooser效能高一點,PowerOfTwoEventExecutorChooser和GenericEventExecutorChooser都是DefaultEventExecutorChooserFactory 的靜態內部類,都有next()方法返回一個EventExecutor。以上是對chooser的建立的一個分析,
回到MultithreadEventExecutorGroup看一下對chooser的賦值:

//虛擬碼
public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
    private final EventExecutor[] children;
    protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
       children = new EventExecutor[nThreads];
         for (int i = 0; i < nThreads; i ++) {
            children[i] = newChild(executor, args);
         }   
        chooser = chooserFactory.newChooser(children);  
    }
}

children的來源是newChild()方法:

    /**
     * Create a new EventExecutor which will later then accessible via the {@link #next()}  method. This method will be
     * called for each thread that will serve this {@link MultithreadEventExecutorGroup}.
     *
     建立一個EventExecutor ,稍後可以呼叫next()方法,這個next()方法被每個執行緒呼叫,這些執行緒 是服務MultithreadEventExecutorGroup的
     */
    protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;

這個是EventExecutor 的建立,接下來我們看一下register方法,我們打了一個斷點:
這裡寫圖片描述
之後debug進入register方法,我們進入的是SingleThreadEventLoop:
這裡寫圖片描述

/**
 * Abstract base class for {@link EventLoop}s that execute all its submitted tasks in a single thread.
 * EventLoop的基礎抽象類,所有提交的任務都會在一個執行緒裡邊執行。
 *
 */
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
...略
    public ChannelFuture register(Channel channel) {
        return register(new DefaultChannelPromise(channel, this));
    }
    ...略
}

DefaultChannelPromise是ChannelFuture的具體實現, 其持有Channel 和當前的EventLoop。

    public DefaultChannelPromise(Channel channel, EventExecutor executor) {
        super(executor);
        this.channel = channel;
    }

父類->

public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
    public DefaultPromise(EventExecutor executor) {
        this.executor = checkNotNull(executor, "executor");
    }
}

最後我們來到register方法:

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop
    public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        promise.channel().unsafe().register(this, promise);
        return promise;
    }
}

這個方法是註冊邏輯的真正的入口了,出現了unsafe物件,下一節介紹。

相關推薦

netty原始碼分析()Channel選擇工廠演算法註冊底層實現

上一節說到註冊的入口,即 MultithreadEventLoopGroup: public ChannelFuture register(Channel channel) { return next().register(chann

第五 css選擇和盒模型

1.組合選擇器 群組選擇器 #每個選擇為可以位三種基礎選擇器任意一個,用逗號隔開,控制多個。 div,#div,.div{     color:red } 後代(子代)選擇器 .sup .sub{     後代 } .sup .sub{  

[Abp 原始碼分析]、後臺作業後臺工作者

0. 簡介 在某些時候我們可能會需要執行後臺任務,或者是執行一些週期性的任務。比如說可能每隔 1 個小時要清除某個臨時資料夾內的資料,可能使用者會要針對某一個使用者群來群發一組簡訊。前面這些就是典型的應用場景,在 Abp 框架裡面為我們準備了後臺作業和後臺工作者來幫助我們解決這個問題。 後臺作業與後臺工作者的

Netty原始碼分析第6章(解碼)---->第3節: 行解碼

  Netty原始碼分析第六章: 解碼器   第三節: 行解碼器   這一小節瞭解下行解碼器LineBasedFrameDecoder, 行解碼器的功能是一個位元組流, 以\r\n或者直接以\n結尾進行解碼, 也就是以換行符為分隔進行解析 同樣, 這個解碼器也繼承了B

Netty原始碼分析第6章(解碼)---->第2節: 固定長度解碼

  Netty原始碼分析第六章: 解碼器   第二節: 固定長度解碼器   上一小節我們瞭解到, 解碼器需要繼承ByteToMessageDecoder, 並重寫decode方法, 將解析出來的物件放入集合中集合, ByteToMessageDecoder中可以將解析出

Netty原始碼分析第6章(解碼)---->第1節: ByteToMessageDecoder

  Netty原始碼分析第六章: 解碼器   概述:           在我們上一個章節遺留過一個問題, 就是如果Server在讀取客戶端的資料的時候, 如果一次讀取不完整, 就觸發channelRead事件, 那麼Netty是

Netty原始碼分析第6章(解碼)---->第4節: 分隔符解碼

  Netty原始碼分析第六章: 解碼器   第四節: 分隔符解碼器     基於分隔符解碼器DelimiterBasedFrameDecoder, 是按照指定分隔符進行解碼的解碼器, 通過分隔符, 可以將二進位制流拆分成完整的資料包   同樣

Netty原始碼分析第7章(編碼和寫資料)---->第2節: MessageToByteEncoder

  Netty原始碼分析第七章: Netty原始碼分析   第二節: MessageToByteEncoder   同解碼器一樣, 編碼器中也有一個抽象類叫MessageToByteEncoder, 其中定義了編碼器的骨架方法, 具體編碼邏輯交給子類實現 解碼器同樣也

Netty原始碼分析第7章(編碼和寫資料)---->第4節: 重新整理buffer佇列

  Netty原始碼分析第七章: 編碼器和寫資料   第四節: 重新整理buffer佇列   上一小節學習了writeAndFlush的write方法, 這一小節我們剖析flush方法 通過前面的學習我們知道, flush方法通過事件傳遞, 最終會傳遞到HeadCon

Spring Security原始碼分析:Spring Security專案實戰

Spring Security是一個能夠為基於Spring的企業應用系統提供宣告式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Contr

netty原始碼分析(七)Netty執行緒模型深度解讀架構設計原則

上次分析到: public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop public ChannelFutu

ABP原始碼分析:DTO的設計

IDTO:空介面,用於標註Dto物件。 ComboboxItemDto:用於combobox/list中Item的DTO NameValueDto<T>/NameValueDto:用於name value鍵值對的DTO, name為string型別, value為泛型或string型別。

Netty原始碼分析)----- 客戶端接入accept過程

通讀本文,你會了解到1.netty如何接受新的請求2.netty如何給新請求分配reactor執行緒3.netty如何給每個新連線增加ChannelHandler netty中的reactor執行緒 netty中最核心的東西莫過於兩種型別的reactor執行緒,可以看作netty中兩種型別的發動機,驅動著

Netty原始碼分析之ChannelPipeline(一)—ChannelPipeline的構造初始化

Netty中ChannelPipeline實際上類似與一條資料管道,負責傳遞Channel中讀取的訊息,它本質上是基於責任鏈模式的設計與實現,無論是IO事件的攔截器,還是使用者自定義的ChannelHandler業務邏輯都做為一個個節點被新增到任務鏈上。 一、ChannelPipeline的設計與構成 &

Netty原始碼分析之ChannelPipeline(二)—ChannelHandler的新增刪除

上篇文章中,我們對Netty中ChannelPipeline的構造與初始化進行了分析與總結,本篇文章我們將對ChannelHandler的新增與刪除操作進行具體的的程式碼分析; 一、ChannelHandler的新增 下面是Netty官方的一段demo原始碼,可以看到在服務端初始化時執行了向Channel

Netty原始碼分析第2章(NioEventLoop)---->第3節: 初始化執行緒選擇

  第二章:NioEventLoop   第三節:初始化執行緒選擇器 回到上一小節的MultithreadEventExecutorGroup類的構造方法: protected MultithreadEventExecutorGroup(int nThreads, Exec

netty原始碼分析(二二)Netty編解碼剖析入站出站處理器詳解

Netty處理器重要概念: 1、Netty的處理器可以分為兩類:入棧處理器和出棧處理器。 2、入棧處理器的頂層是ChannelInboundHandler,出棧處理器的頂層是ChannelOutboundHandler。 3、資料處理時常用的各種編解碼器本

Netty原始碼分析--Channel註冊(中)(

        接上一篇,我們繼續看          不知道大家第一次看這段程式碼的時候有沒有一臉懵逼,反正我是一臉懵,為什麼這個if else 最終都是呼叫的register0方法,都是一樣的。 &

Netty原始碼分析)----- 拆包之LineBasedFrameDecoder

Netty 自帶多個粘包拆包解碼器。今天介紹 LineBasedFrameDecoder,換行符解碼器。 行拆包器 下面,以一個具體的例子來看看業netty自帶的拆包器是如何來拆包的 這個類叫做 LineBasedFrameDecoder,基於行分隔符的拆包器,TA可以同時處理 \n

Netty原始碼分析一)----- 拆包之LengthFieldBasedFrameDecoder

本篇文章主要是介紹使用LengthFieldBasedFrameDecoder解碼器自定義協議。通常,協議的格式如下: LengthFieldBasedFrameDecoder是netty解決拆包粘包問題的一個重要的類,主要結構就是header+body結構。我們只需要傳入正確的引數就可以傳送和接收正確