netty 耗時任務如何處理

netty 處理耗時的任務邏輯,是不能在IO線程處理,由於這會形成堵塞,將會嚴重影響性能。那怎麼區分IO線程呢?
答案就是EventLoop,EventLoop用來處理IO線程,所以耗時任務的handler不要在EventLoop裏面處理。
如下面代碼爲例:html

bossGroup = new NioEventLoopGroup();
 workerGroup = new NioEventLoopGroup();

 try {
    ServerBootstrap bootstrap = new ServerBootstrap();
    bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
 ....

其中workerGroup就是專門用來處理IO線程業務邏輯的,例如執行一些 編碼、解碼 等不耗時的業務處理。bootstrap

若是有處理耗時任務的handler應該怎麼辦?
能夠專門開一個線程池,來專門處理耗時業務。Netty Api 已經提供了一些說明,http://netty.io/4.1/api/index...,ChannelPipeline中 能夠找到以下描述:api

A user is supposed to have one or more ChannelHandlers in a pipeline to receive I/O events (e.g. read) and to request I/O operations (e.g. write and close). For example, a typical server will have the following handlers in each channel's pipeline, but your mileage may vary depending on the complexity and characteristics of the protocol and business logic:安全

Protocol Decoder - translates binary data (e.g. ByteBuf) into a Java object.
Protocol Encoder - translates a Java object into binary data.
Business Logic Handler - performs the actual business logic (e.g. database access).
and it could be represented as shown in the following example:
static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
...async

ChannelPipeline pipeline = ch.pipeline();

 pipeline.addLast("decoder", new MyProtocolDecoder());

 pipeline.addLast("encoder", new MyProtocolEncoder());

 // Tell the pipeline to run MyBusinessLogicHandler's event handler methods
 // in a different thread than an I/O thread so that the I/O thread is not blocked by
 // a time-consuming task.
 // If your business logic is fully asynchronous or finished very quickly, you don't
 // need to specify a group.
 pipeline.addLast(group, "handler", new MyBusinessLogicHandler());

其中EventExecutorGroup 就是專門來處理耗時業務的線程池。ide

在實際生產環境中,咱們可能會碰到 須要臨時執行也行計劃任務,,這些任務若是不耗時,咱們能夠經過channel提供的計劃任務方法處理:oop

future =  channel.eventLoop.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                            //邏輯代碼,非耗時任務
               }
        }, 6, 6, TimeUnit.HOURS);
       ....

若是計劃任務裏面的邏輯比較耗時,那麼就不能再用eventLoop,由於這會阻塞IO線程。若是是經過pipeline.addLast(group, "handler", new MyBusinessLogicHandler()); 這種方式添加的業務線程咱們能夠使用下面的方式添加計劃任務方法實現:性能

***future = ctx.executor().scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
            }
        }, 6, 6, TimeUnit.HOURS);***

...ui

netty 源碼this

public EventExecutor executor() {
        return (EventExecutor)(this.executor == null?this.channel().eventLoop():this.executor);
    }

若是this.executor爲null,就返回channel().eventLoop(),這個是io讀寫線程,確定是不能執行耗時任務的。
若是不爲空,那麼是怎麼傳進來的呢?

DefaultChannelPipeline

public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized(this) {
            checkMultiplicity(handler);
            newCtx = this.newContext(group, this.filterName(name, handler), handler);

DefaultChannelPipeline 的addLast(EventExecutorGroup group, String name, ChannelHandler handler)爲例,該方法部分源碼以下

@Override
    public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
            checkMultiplicity(handler);

            newCtx = newContext(group, filterName(name, handler), handler);

            addLast0(newCtx);
   ...代碼略去...
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
        return new DefaultChannelHandlerContext(this, this.childExecutor(group), name, handler);
    }

經過源碼發現:其實就是咱們在添加handler時指定的DefaultEventExecutorGroup。
因此結論是:若是在處理耗時任務的Handler添加時用到了DefaultEventExecutorGroup是能夠 ctx.executor().scheduleAtFixedRate這麼用的,可是若是你再添加handler時沒有沒有指定特殊的EventExecutorGroup,是不能執行耗時任務的。

若是是在IO線程,若是想處理耗時任務邏輯,那麼就須要新建一個EventExecutorGroup,並調用他的相關方法


EventLoop:其本質是一個用來處理IO事件的線程,EventLoopGroup 其本質是一個線程池。一個EventLoop能夠和多個Channel綁定,處理多個Channel的IO事件;可是一個Channel在整個生命週期內只會被一個EventLoop處理,這就也就保證了線程安全。

相關文章
相關標籤/搜索