V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gramyang
V2EX  ›  Java

netty 处理耗时任务的问题

  •  
  •   gramyang · 2019-04-15 14:46:53 +08:00 · 3329 次点击
    这是一个创建于 2074 天前的主题,其中的信息可能已经有所发展或是发生改变。
    netty 处理任务一般在 worker 线程里,对于在 netty 中如何使用线程池来处理耗时任务我觉得这篇文章说的可以: https://www.jianshu.com/p/727bbc7454dc

    但是问题来了,encode 和 decode 方法算不算耗时任务?有的文章说算,有的文章说不算。我认为 encode 和 decode 姑且也应该算耗时任务吧,请教一下大家的意见
    10 条回复    2019-04-16 07:34:04 +08:00
    javapythongo
        1
    javapythongo  
       2019-04-15 15:13:30 +08:00
    encode 算什么耗时任务。。。又不费 cpu、又没 io
    loveCoding
        2
    loveCoding  
       2019-04-15 15:18:32 +08:00
    不算,但是编码 /解码有很多优化技巧在里面.
    jimrok
        3
    jimrok  
       2019-04-15 15:27:55 +08:00   ❤️ 1
    netty 这种东西就是异步 IO,也就是在 decode 时,已经完成了数据的接收。decode 只是利用 cpu 做一些计算完成 byte 的转换。cpu 干这种事情是非常块的,也不需要其他子源参与。一旦你做完了 decode 得到了需要的 java 对象,那可能你会去做业务处理,例如数据库的查询,这里会阻塞 worker 线程,那么另外的连接就必须排队 decode,所以,要想让并发量高,你需要用另外的线程池去干业务的事情,或者分发给其他的服务器来做。
    gramyang
        4
    gramyang  
    OP
       2019-04-15 15:38:37 +08:00
    @jimrok 顺便请教一个问题:现在有两种方式来并发处理 channelhandler,一个是用 EventExecutor ;还有一种方法是用 worker 线程的 eventloop,就是 ctx.executor。第二种方法会不会影响到 worker 线程组的接收请求的效率呢?
    wucao219101
        5
    wucao219101  
       2019-04-15 15:44:11 +08:00
    encode 和 decode 不算,没有 IO。
    jimrok
        6
    jimrok  
       2019-04-15 16:32:57 +08:00
    @gramyang 我对 netty 不了解的。好像两者没有差别,除非是 ctx 上的 executor 被替换了默认的实现。
    gz911122
        7
    gz911122  
       2019-04-15 16:49:56 +08:00
    内存操作都不算耗时任务
    耗时任务一般指 io

    一个简单粗暴的判断标准:任何涉及到 IO 操作的代码,都可以认为是可能造成阻塞的代码,纯粹内存操作的代码,只要执行时间没有明显超长(例如执行循环几万次的处理便可认为是执行时间超长),都可以认为是非阻塞代码。
    zhaishunqi
        8
    zhaishunqi  
       2019-04-15 17:26:33 +08:00
    @gramyang
    decode 和 codec 就不说了.
    两种方法个人感觉是不会有太大影响的.

    Netty 的 BossGroup 和 WorkerGroup 主要用来保证系统的 IO 性能,就是所谓的 IO 线程池,只要不直接在这两个线程池里面进行耗时的操作,应该不会影响 netty 的 io 性能.

    netty 启动的时候,配置了一个 BossGroup 和 WorkerGroup,伪代码如下:
    ```java
    // 设置 NIO
    serverBootstrap.channel(NioServerSocketChannel.class);
    // 设置多线程模型
    serverBootstrap.group(nettyConfig.getBossGroup(), nettyConfig.getWorkerGroup());
    // 设置 handler 集合
    serverBootstrap.childHandler(initializerFactory);
    ```
    在增加 ctx 的时候,增加了业务线程池,如下:

    ```java
    protected void initChannel(Channel arg0){
    arg0.pipeline()
    // 业务处理控制器
    .addLast(businessGroup,new BusinessHandler());
    }

    按照你给的简书的那部分说明,找到对应源码:
    ```java
    static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
    final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
    next.invokeChannelRead(m);
    } else {
    executor.execute(new Runnable() {
    public void run() {
    next.invokeChannelRead(m);
    }
    });
    }

    }
    ```

    `if (executor.inEventLoop()) {`这个分支在 addLast 时,增加了业务线程池以后,是会走下面的 else 的.

    所以,我个人觉得,写在 handler 和 ctx 的线程池,实际上都是脱离了 netty 的核心 io 线程池的.并不会影响 netty 的 io 和并发吞吐量.
    至于性能上的影响,在硬件配置相同的情况下.
    写在 ctx 和写在 handler 的线程池的性能差别,主要看你在 handler 交给线程池前,做了什么耗时的操作没有.否则效果应该没差别.

    PS:
    回复不知道支持不支持 md 语法...
    gramyang
        9
    gramyang  
    OP
       2019-04-15 17:38:16 +08:00
    @zhaishunqi 很精准,谢谢
    runningman
        10
    runningman  
       2019-04-16 07:34:04 +08:00 via iPhone
    不知道都咋玩的 可以交流交流 目前线上没问题
    但是不知道是否还能优化 微信 270115861
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5462 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 01:23 · PVG 09:23 · LAX 17:23 · JFK 20:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.