Netty案例(二)之耗时任务的处理

2023-11-08

netty版本

  1. 使用的netty版本是io.netty:netty-all:4.1.33.Final

Netty耗时任务的处理

  1. Netty中EventLoop用来处理IO线程,因此handler中的耗时任务(比如数据库连接、远程调用等)不能在EventLoop里面执行。如果有耗时任务,需要将耗时任务添加到业务线程池中执行。
  2. 处理耗时任务的两种方式
    • Handler中加入线程池
    • Context中添加线程池
  3. 两种方式的对比
    • Handler中自定义业务线程池更加灵活,每个Handler都可以自己控制自己的业务线程池,对于非耗时的任务可以不使用业务线程池,直接在EventLoop线程中执行。
    • Context中添加线程池(Netty建议的方式),在pipeline中添加Handler的时候,添加一个业务线程池。这种方式Handler中的代码不需要做任何修改,但是整个Handler都交给业务线程池,无论是否是耗时任务都会加入到队列里,控制的粒度比较粗。
  4. 如果业务ChannelHandler处理逻辑比较简单,执行时间是受控的,业务I/O线程的负载也不重,在这种应用场景下,业务ChannelHandler可以和I/O操作共享同一个线程。使用这种线程模型会带来两个优势:
    • 开发简单,开发业务ChannelHandler的不需要关注Netty的线程模型
    • 性能更高:因为减少了一次线程上下文切换,所以性能会更高。
  5. Netty线程池的特点
    • ChannelEventLoopN:1的关系:一个Channel生命周期内只注册一个EventLoop,一个EventLoop可能会给分配给多个Channel,所以如果一个Channel阻塞可能会导致其他在同一个EventLoop上的Channel都阻塞。
    • 一个EventLoopGroup包含一个或者多个EventLoop,一个EventLoop在其生命周期内只与一个Thread绑定(EbeddedEventLoop除外)EventLoopThread负责处理该事件循环内所有的IO事件

代码案例

Handler自定义业务线程池

  1. Handler中自定义业务线程池

        @ChannelHandler.Sharable
        public class EchoServerHandler extends SimpleChannelInboundHandler<String> {
            public static final ChannelHandler INSTANCE = new EchoServerHandler();
            private static final String LINE = System.getProperty("line.separator");
        
            private EchoServerHandler() {
            }
            protected static ExecutorService newFixedThreadPool() {
                final ThreadFactory threadFactory = new ThreadFactoryBuilder()
                        .setNameFormat("netty-business-%d")
                        .setDaemon(false)
                        .build();
                return new ThreadPoolExecutor(200, 200,
                        0L, TimeUnit.MILLISECONDS,
                        new LinkedBlockingQueue<Runnable>(10000),
                        threadFactory);
            }
            final static ListeningExecutorService service = MoreExecutors.listeningDecorator(newFixedThreadPool());
            @Override
            public void channelRead0(ChannelHandlerContext ctx, String msg) {
                service.submit(new Runnable() {
                    @Override
                    public void run() {
                        //模拟耗时任务
                        try {
                            Thread.sleep(5000);
                            logger.info("execute time 5s");
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                        ctx.writeAndFlush(msg + LINE).addListener(ChannelFutureListener.CLOSE);
                    }
                });
        
            }
        }
    
  2. Server启动代码

        public class EchoServer {
        
            private final int port;
        
            public EchoServer(int port) {
                this.port = port;
            }
        
            public void start() throws Exception {
                NioEventLoopGroup boss = new NioEventLoopGroup(1);
                NioEventLoopGroup worker = new NioEventLoopGroup();
                try {
                    ServerBootstrap b = new ServerBootstrap();
                    b.group(boss, worker)
                            .channel(NioServerSocketChannel.class)
                            .localAddress(new InetSocketAddress(port))
                            .childHandler(new ChannelInitializer<SocketChannel>() {
                                @Override
                                public void initChannel(SocketChannel ch) {
                                    ChannelPipeline pipeline = ch.pipeline();
                                    pipeline.addLast(new LineBasedFrameDecoder(1024));
                                    pipeline.addLast(new StringDecoder());
                                    pipeline.addLast(new StringEncoder());
                                    pipeline.addLast(EchoServerHandler.INSTANCE);
        
        
                                }
                            });
                    ChannelFuture f = b.bind().sync();
                    System.out.println(String.format("%s started and listen on %s", EchoServer.class.getName(), f.channel().localAddress()));
                    f.channel().closeFuture().sync();
                } finally {
                    boss.shutdownGracefully().sync();
                    worker.shutdownGracefully().sync();
                }
            }
        
            public static void main(String[] args) throws Exception {
                new EchoServer(8080).start();
            }
        }
    
  3. 使用多个telnet连接并请求,输出结果,可以看出执行任务使用的是我们自己定义的线程池

        netty-business-0 execute time 5s
        netty-business-1 execute time 5s
    

Context中添加线程池

  1. Handler代码无需任何的改动,不需要启动任何额外线程来处理任务

        @ChannelHandler.Sharable
        public class EchoServerHandler extends SimpleChannelInboundHandler<String> {
            public static final ChannelHandler INSTANCE = new EchoServerHandler();
            private static final String LINE = System.getProperty("line.separator");
        
            private EchoServerHandler() {
            }
            @Override
            public void channelRead0(ChannelHandlerContext ctx, String msg) {
                //模拟耗时任务
                try {
                    Thread.sleep(5000);
                    System.out.printf("%s execute time 5s \n", Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                ctx.writeAndFlush(msg + LINE).addListener(ChannelFutureListener.CLOSE);
            }
        }
        
    
  2. 启动代码

        public class EchoServer {
           private final int port;
           public EchoServer(int port) {
               this.port = port;
           }
           public void start() throws Exception {
               final ThreadFactory threadFactory = new ThreadFactoryBuilder()
                   .setNameFormat("netty-context-business-%d")
                   .setDaemon(false)
                   .build();
               NioEventLoopGroup boss = new NioEventLoopGroup(1);
               NioEventLoopGroup worker = new NioEventLoopGroup();
               NioEventLoopGroup business = new NioEventLoopGroup(200,threadFactory);
               try {
                   ServerBootstrap b = new ServerBootstrap();
                   b.group(boss, worker)
                           .channel(NioServerSocketChannel.class)
                           .localAddress(new InetSocketAddress(port))
                           .childHandler(new ChannelInitializer<SocketChannel>() {
                               @Override
                               public void initChannel(SocketChannel ch) {
                                   ChannelPipeline pipeline = ch.pipeline();
                                   pipeline.addLast(new LineBasedFrameDecoder(1024));
                                   pipeline.addLast(new StringDecoder());
                                   pipeline.addLast(new StringEncoder());
                                   pipeline.addLast(business, EchoServerHandler.INSTANCE);
       
       
                               }
                           });
                   ChannelFuture f = b.bind().sync();
                   System.out.println(String.format("%s started and listen on %s", EchoServer.class.getName(), f.channel().localAddress()));
                   f.channel().closeFuture().sync();
               } finally {
                   boss.shutdownGracefully().sync();
                   worker.shutdownGracefully().sync();
                   business.shutdownGracefully().sync();
               }
           }
       
           public static void main(String[] args) throws Exception {
               new EchoServer(8080).start();
           }
       }
       
    
    
  3. 使用多个telnet连接并请求,输出结果

        netty-context-business-0 execute time 5s 
        netty-context-business-1 execute time 5s 
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Netty案例(二)之耗时任务的处理 的相关文章

  • 关于海康,宇视,天地伟业摄像头调试

    最近在项目中需要读取摄像机的内容 现有的摄像机有海康威视 宇视 和天地伟业三家的摄像机 一开始 天地伟业和宇视都给了demo 即html和css代码 是可以读取视频流的 但是海康威视没有给demo 只是告诉我们可以通过vlc来读取视频流的内

随机推荐

  • 使用Inno Setup 打包成exe安装包+执行外部脚本文件

    有时候我们将软件需要做成类似下载后双击就能安装的程序 那么就需要使用打包工具进行打包 打包工具很多 有的简单 有的过程也比较复杂 如果有能力 自己可以写一个安装器 类似腾讯视频 优酷视频 哔哩哔哩的PC安装界面 这种就特别高大上 今天 主要
  • c++调用mxnet模型做预测

    python在深度学习领域很火 做实验用python很舒服 但是生产环境下可能还是需要c c 那么问题来了 mxnet训练出来的模型如何在c c 下调用 以下是一些填坑的经验分享一下 mxnet支持c c 调用模型 但目前不是全部的网络模型
  • 双向可控硅的四象限触发方式

    双向可控硅的四象限触发方式 双向可控硅是在普通可控硅的基础上发展而成的 它不仅能代替两只反极性并联的可控硅 而且仅需一个触发电路 是目前比较理想的交流开关器件 其英文名称TRIAC即三端双向交流开关之意 尽管从形式上可将双向可控硅看成两只普
  • SpringBoot入门到项目实战,带你快速上手springboot

    动力节点王鹤老师的SpringBoot入门系列课程 通俗易懂 基于SpringBoot2 4版本讲解 从细节入手 每个事例先讲解pom xml中的重要依赖 其次application配置文件 最后是代码实现 让你知其所以 逐步让掌握Spri
  • 适合Python 的5大练手项目,你练了么?

    往期好文推荐 0基础不用怕 从0到1轻松教你入门Python python系统学习流线图 教你一步一步学会python 但是在练手项目的选择上 还存在疑问 不知道要从哪种项目先下手 python教程入门学习 首先有两点建议 最好不要写太应用
  • ios后台运行

    iOS在升级到4 0以后就支持了多任务了 下文将详细介绍一下这个特性 1 检查设备是否支持多任务 Apple出于性能的考虑 并不是所有的iOS设备升级到iOS4以后都支持多任务 比如iPhone 3G 如果你的应用在没有多任务特性时会出问题
  • Nv21转Bitmap(高效率转化)

    转自 https blog csdn net qq1137830424 article details 81980673 版权声明 本文为博主原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接和本声明 本文链接 ht
  • 广义线性回归模型之0,1变量回归(logit/probit回归)—R语言实现

    1 广义线性回归 广义线性模型有三个组成部分 1 随机部分 即变量所属的指数族分布 族成员 诸如正态分布 二项分布 Poisson 分布等等 2 线性部分 即 x 3 连接函数 g R 中的广义线性模型函数glm 对指数族中某分布的默认连接
  • Redis的发布订阅模式:实现消息队列和实时数据推送的利器

    当涉及到实时数据推送和消息队列时 Redis的发布订阅模式是一种非常有用的工具 Redis是一个开源的内存数据库 被广泛用于缓存 队列和实时数据处理等方面 在本博客中 我们将重点介绍Redis的发布订阅模式 并且提供一些示例代码来帮助读者更
  • pandoc -crossref插件实现markdwon文档转word后公式编号自定义

    pandoc crossref插件实现markdwon文档转word后公式编号自定义 借助markdown撰写论文还是有一些优势的 公式可以通过vscode 提示直接快速地写出来 图片按照链接插入以后就可以自动更新图源 论文提交的时候需要转
  • Aviator 常见使用

    学习使用AviatorScript 写脚本对数据进行处理 这边写一些常见的例子 都使用表达式的方式 使用文本的话 无法传具体的参数 aviator maven最新的引用
  • 基于stm32单片机汽车胎压温度检测Proteus仿真程序

    采用stm32单片机作为主控CPU 采用BMP180传感器来测量气压和温度 采用LCD1602显示气压和温度 并且通过串口打印框也可以显示当前的气压和温度 完美的模拟出汽车胎压和温度检测相关功能 程序采用keil5编写 并且有中文注释 新手
  • [XAMPP的安装及使用教程] BUG解决

    说明 XAMPP的安装及使用教程 https blog csdn net qq 36595013 article details 80373597 转载 本文是针对原博客连接如上 安装过程中出现的bug进行解决 BUG1 前提 mysql端
  • 基于深度学习的高精度课堂人脸检测系统(PyTorch+Pyside6+YOLOv5模型)

    摘要 基于深度学习的高精度课堂人脸检测系统可用于日常生活中或野外来检测与定位课堂人脸目标 利用深度学习算法可实现图片 视频 摄像头等方式的课堂人脸目标检测识别 另外支持结果可视化与图片或视频检测结果的导出 本系统采用YOLOv5目标检测模型
  • 1084. 销售分析III(SQL)

    题目 https leetcode cn com problems sales analysis iii Table Product Column Name Type product id int product name varchar
  • demo演示是什么意思_路演(融资演示)时要注意些什么?

    路演 融资演示 究竟重不重要 如果你的企业足够优秀 那可能路演对你来说就没那么重要 甚至都不需要路演 可能就有很多投资人抢着来投你 但能达到这个水平的毕竟是少数 更多的是默默无闻的创业者 如果你的企业还没有那么优秀 或者你的产品还不够成熟
  • Python_捕获未知错误代码

    try num int input 请输入一个整数 result 8 num print result except Exception as result print 未知错误 s result
  • VScode编译调试C++环境

    首先去官网下载vscodehttps code visualstudio com 为了编译C C 要使用gcc Windows本身不支持gcc 所以有了MinGW 我用的是dev带的MinGW 也可以自己安装MinGW 或者用VS的编译器
  • VTM7.0配置并运行(windows系统)

    文章目录 一 下载安装VTM 下载方式一 下载方式二 1 解压VTM软件压缩包 2 在解压好的目录里新建 build 文件夹 二 下载安装Cmake 1 下载Cmake并解压 2 配置Cmake环境变量 三 编译 方法一 界面 1 打开 c
  • Netty案例(二)之耗时任务的处理

    文章目录 netty版本 Netty耗时任务的处理 代码案例 Handler 自定义业务线程池 Context中添加线程池 netty版本 使用的netty版本是io netty netty all 4 1 33 Final Netty耗时