標籤:ada public cti loop 如何 狀態 config 比較 sel
分析NioEventLoopGroup最主有兩個疑問
1.next work如何分配NioEventLoop
2.boss group 與child group 是如何協作啟動並執行
從EventLoopGroup介面約定通過register方法從channel或promise轉換成ChannelFuture對象
next方法就是用來分配NioEventLoop
public interface EventLoopGroup extends EventExecutorGroup { @Override EventLoop next(); ChannelFuture register(Channel channel); ChannelFuture register(ChannelPromise promise); @Deprecated ChannelFuture register(Channel channel, ChannelPromise promise);}
為了節省篇副,做了代碼整理
1.NioEventLoopGroup構造時綁定SelectorProvider.provider(),通過newChild產生單個EventLoop
2.next實現是個環形迴圈
3.register方法是將channel轉換成ChannelFuture
讀者如果感興趣可以在這幾個方法打上斷點看看
public class NioEventLoopGroup extends MultithreadEventLoopGroup { public NioEventLoopGroup(int nThreads, Executor executor) { this(nThreads, executor, SelectorProvider.provider()); } @Override protected EventLoop newChild(Executor executor, Object... args) throws Exception { return new NioEventLoop(this, executor, (SelectorProvider) args[0], ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]); } /////////////////////////////GenericEventExecutorChooser實現next////////////////////////////////// @Override public EventExecutor next() { return executors[Math.abs(idx.getAndIncrement() % executors.length)]; } /////////////////////////////SingleThreadEventLoop實現register////////////////////////////////// @Override public ChannelFuture register(Channel channel) { return register(new DefaultChannelPromise(channel, this)); } @Override public ChannelFuture register(final ChannelPromise promise) { ObjectUtil.checkNotNull(promise, "promise"); promise.channel().unsafe().register(this, promise); return promise; }}
我們用過程的方式來類比NioEventLoopGroup使用
如果讀者有印象netty server 至少有兩組NioEventLoopGroup 一個是boss 另一個是child
public class TestBossChildGroup { static SocketAddress address = new InetSocketAddress("localhost", 8877); @Test public void server() throws IOException { SelectorProvider bossProvider = SelectorProvider.provider(); SelectorProvider childProvider = SelectorProvider.provider(); int count = 2; AbstractSelector bossSelector = bossProvider.openSelector(); AbstractSelector[] childSelectors = new AbstractSelector[count]; for (int i = 0; i < count; i++) { childSelectors[i] = childProvider.openSelector(); } //server綁定訪問連接埠 並向Selector註冊OP_ACCEPT ServerSocketChannel serverSocketChannel = bossProvider.openServerSocketChannel(); serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(address); serverSocketChannel.register(bossSelector, SelectionKey.OP_ACCEPT); int i = 0; while (true) { int s = bossSelector.select(300); if (s > 0) { Set<SelectionKey> keys = bossSelector.selectedKeys(); Iterator<SelectionKey> it = keys.iterator(); while (it.hasNext()) { SelectionKey key = it.next(); //為什麼不用elseIf 因為 key interestOps 是多重疊狀態,一次返回多個操作 if (key.isAcceptable()) { System.out.println("isAcceptable"); //這裡比較巧妙,註冊OP_READ交給別一個Selector處理 key.channel().register(childSelectors[i++ % count], SelectionKey.OP_READ); } //這部分是child eventLoop處理 if (key.isConnectable()) { System.out.println("isConnectable"); } if (key.isWritable()) { System.out.println("isWritable"); } if (key.isReadable()) { System.out.println("isReadable"); } key.interestOps(~key.interestOps()); it.remove(); } } } } @Test public void client() throws IOException { SocketChannel clientSocketChannel = SelectorProvider.provider().openSocketChannel(); clientSocketChannel.configureBlocking(true); clientSocketChannel.connect(address); }}
[編織訊息架構][netty源碼分析]5 EventLoopGroup 實作類別NioEventLoopGroup職責與實現