资讯专栏INFORMATION COLUMN

netty 耗时任务如何处理

Travis / 2699人阅读

摘要:如果有处理耗时任务的应该怎么办可以专门开一个线程池,来专门处理耗时业务。如果是在线程,如果想处理耗时任务逻辑,那么就需要新建一个并调用他的相关方法其本质是一个用来处理事件的线程,其本质是一个线程池。

netty 处理耗时的任务逻辑,是不能在IO线程处理,因为这会造成堵塞,将会严重影响性能。那怎么区分IO线程呢?
答案就是EventLoop,EventLoop用来处理IO线程,因此耗时任务的handler不要在EventLoop里面处理。
以下面代码为例:

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

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

其中workerGroup就是专门用来处理IO线程业务逻辑的,例如执行一些 编码、解码 等不耗时的业务处理。

如果有处理耗时任务的handler应该怎么办?
可以专门开一个线程池,来专门处理耗时业务。Netty Api 已经提供了一些说明,http://netty.io/4.1/api/index...,ChannelPipeline中 可以找到如下描述:

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);
...

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 就是专门来处理耗时业务的线程池。

在实际生产环境中,我们可能会碰到 需要临时执行也行计划任务,,这些任务如果不耗时,我们可以通过channel提供的计划任务方法处理:

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);***

...

netty 源码

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处理,这就也就保证了线程安全。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66451.html

相关文章

  • Netty AUTO_READ读数据流程分析

    摘要:用这种方式很好的规避了多线程所带来的问题,很值得我们借鉴那么这个怎么来的呢看一下的方法如果为,就返回。 Netty channelRegisteredChannelActive---源码分析经过下面的分析我们可以了解netty读数据的一个过程,以及为什么channelActive方法、channelReadComplete方法会回调ChannelOutboundHandler的read...

    fevin 评论0 收藏0
  • 为Java程序员金三银四精心挑选的300余道Java面试题与答案

    摘要:为程序员金三银四精心挑选的余道面试题与答案,欢迎大家向我推荐你在面试过程中遇到的问题我会把大家推荐的问题添加到下面的常用面试题清单中供大家参考。 为Java程序员金三银四精心挑选的300余道Java面试题与答案,欢迎大家向我推荐你在面试过程中遇到的问题,我会把大家推荐的问题添加到下面的常用面试题清单中供大家参考。 前两天写的以下博客,大家比较认可,热度不错,希望可以帮到准备或者正在参加...

    tomorrowwu 评论0 收藏0
  • Netty 源码分析之 三 我就是大名鼎鼎的 EventLoop(二)

    摘要:接上篇源码分析之三我就是大名鼎鼎的一的处理循环在中一个需要负责两个工作第一个是作为线程负责相应的操作第二个是作为任务线程执行中的任务接下来我们先从操纵方面入手看一下数据是如何从传递到我们的中的是模型的一个实现并且是基于的那么从的前生今世之四 接上篇Netty 源码分析之 三 我就是大名鼎鼎的 EventLoop(一) Netty 的 IO 处理循环 在 Netty 中, 一个 Even...

    whidy 评论0 收藏0
  • 高级架构师实战:何用最小的代价完成爬虫需求

    摘要:在系统正常运行时,可以变更爬虫的配置,一旦实时监控爬虫出现异常,可实时修正配置进行干预。从数据库中实时读取配置信息,响应业务层的配置请求。处理系统通过服务层,每次去取配置信息可能维护人员在实时修正及待抓取的列表进行处理。 showImg(https://segmentfault.com/img/bVLa4V?w=960&h=540); 一  缘起 在我工作的多家公司,有众多的领域,如房...

    light 评论0 收藏0

发表评论

0条评论

Travis

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<