Netty之Channel解读

news2024/11/24 3:03:39

目录

channel 的主要作用

ChannelFuture

CloseFuture

为什么要异步关闭


channel 的主要作用

  • close() 可以用来关闭 channel
  • closeFuture() 用来处理 channel 的关闭
    • sync 方法作用是同步等待 channel 关闭
    • 而 addListener 方法是异步等待 channel 关闭
  • pipeline() 方法添加处理器
  • write() 方法将数据写入
  • writeAndFlush() 方法将数据写入并刷出

ChannelFuture

下面是一段客户端的代码

new Bootstrap()
    .group(new NioEventLoopGroup())
    .channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<Channel>() {
        @Override
        protected void initChannel(Channel ch) {
            ch.pipeline().addLast(new StringEncoder());
        }
    })
    .connect("127.0.0.1", 8080)
    .sync()
    .channel()
    .writeAndFlush(new Date() + ": hello world!");

现在把它拆开来看

ChannelFuture channelFuture = new Bootstrap()
    .group(new NioEventLoopGroup())
    .channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<Channel>() {
        @Override
        protected void initChannel(Channel ch) {
            ch.pipeline().addLast(new StringEncoder());
        }
    })
    .connect("127.0.0.1", 8080); // 1

channelFuture.sync().channel().writeAndFlush(new Date() + ": hello world!");

1 处返回的是 ChannelFuture 对象,它的作用是利用 channel() 方法来获取 Channel 对象 

注意 connect 方法是异步的,意味着不等连接建立,方法执行就返回了。因此 channelFuture 对象中不能【立刻】获得到正确的 Channel 对象

实验如下:

ChannelFuture channelFuture = new Bootstrap()
    .group(new NioEventLoopGroup())
    .channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<Channel>() {
        @Override
        protected void initChannel(Channel ch) {
            ch.pipeline().addLast(new StringEncoder());
        }
    })
    .connect("127.0.0.1", 8080);

System.out.println(channelFuture.channel()); // 1
channelFuture.sync(); // 2
System.out.println(channelFuture.channel()); // 3
  • 执行到 1 时,连接未建立,打印 [id: 0x2e1884dd]
  • 执行到 2 时,sync 方法是同步等待连接建立完成
  • 执行到 3 时,连接肯定建立了,打印 [id: 0x2e1884dd, L:/127.0.0.1:57191 - R:/127.0.0.1:8080]

除了用 sync 方法可以让异步操作同步以外,还可以使用回调的方式:

ChannelFuture channelFuture = new Bootstrap()
    .group(new NioEventLoopGroup())
    .channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<Channel>() {
        @Override
        protected void initChannel(Channel ch) {
            ch.pipeline().addLast(new StringEncoder());
        }
    })
    .connect("127.0.0.1", 8080);
System.out.println(channelFuture.channel()); // 1
channelFuture.addListener((ChannelFutureListener) future -> {
    System.out.println(future.channel()); // 2
});
  • 执行到 1 时,连接未建立,打印 [id: 0x749124ba]
  • ChannelFutureListener 会在连接建立时被调用(其中 operationComplete 方法),因此执行到 2 时,连接肯定建立了,打印 [id: 0x749124ba, L:/127.0.0.1:57351 - R:/127.0.0.1:8080]

CloseFuture

关闭是由另外一个线程来进行处理的,跟上面的原理一样

 

 

 这里可以看出CLOSE之前就执行了关闭操作

正确关闭的第一种方式:同步关闭处理

      ChannelFuture closeFuture = channel.closeFuture();
        closeFuture.sync();
        log.debug("处理关闭以后的操作"); 

正确关闭的第二种方式:异步关闭处理

   closeFuture.addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture future) throws Exception {
                log.debug("处理关闭以后的操作");
                group.shutdownGracefully();
            }
        });

上述的测试代码

@Slf4j
public class CloseFutureClient {
    public static void main(String[] args) throws Exception{
        NioEventLoopGroup group = new NioEventLoopGroup();
        ChannelFuture channelFuture = new Bootstrap()
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
                        ch.pipeline().addLast(new StringEncoder());
                    }
                }).connect(new InetSocketAddress("localhost", 8080));
        Channel channel = channelFuture.sync().channel();
        log.debug("{}",channel);
        new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            while (true){
                String line = scanner.nextLine();
                if("q".equals(line)){

                    channel.close();//close异步操作
                    log.debug("处理关闭之后的操作");//不能在这里善后 错误的
                    break;
                }
            }
        },"input").start();

        //获取CloseFuture对象
        //1)同步关闭处理
        //2)异步关闭处理
    /*    ChannelFuture closeFuture = channel.closeFuture();
        closeFuture.sync();
        log.debug("处理关闭以后的操作"); */

        ChannelFuture closeFuture = channel.closeFuture();
        closeFuture.addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture future) throws Exception {
                log.debug("处理关闭以后的操作");
                group.shutdownGracefully();
            }
        });

    }
}

为什么要异步关闭

为什么不在一个线程中去执行建立连接、去执行关闭 channel,那样不是也可以吗?非要用这么复杂的异步方式:比如一个线程发起建立连接,另一个线程去真正建立连接。

还有人会笼统地回答,因为 netty 异步方式用了多线程、多线程就效率高。其实这些认识都比较片面,多线程和异步所提升的效率并不是所认为的

思考下面的场景,4 个医生给人看病,每个病人花费 20 分钟,而且医生看病的过程中是以病人为单位的,一个病人看完了,才能看下一个病人。假设病人源源不断地来,可以计算一下 4 个医生一天工作 8 小时,处理的病人总数是:4 * 8 * 3 = 96

经研究发现,看病可以细分为四个步骤,经拆分后每个步骤需要 5 分钟,如下

因此可以做如下优化,只有一开始,医生 2、3、4 分别要等待 5、10、15 分钟才能执行工作,但只要后续病人源源不断地来,他们就能够满负荷工作,并且处理病人的能力提高到了 4 * 8 * 12 效率几乎是原来的四倍,(一个小时内接待病人的效率大大提高,四个医生不是同时工作,但都要干满8小时才下班)

 

要点

  • 单线程没法异步提高效率,必须配合多线程、多核 cpu 才能发挥异步的优势,单线程不能同时处理多个任务,因此无法实现异步处理提高效率。异步处理需要利用多线程或多进程机制来实现,以便同时处理多个任务。多线程或多进程能够允许程序同时执行多个操作,从而提高效率。
  • 异步并没有缩短响应时间,反而有所增加,异步可以提高系统的吞吐量,即能够同时处理多个请
  • 合理进行任务拆分,也是利用异步的关键

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/622592.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用CodeAnt查找并修复IDE中的开源漏洞与许可证合规问题

不断加快的开发步伐正在将软件安全的责任转移到开发人员的桌面上&#xff0c;但是处理在下游构建和测试中检测到的安全问题可能是非常具有破坏性的。直至报告漏洞的时候&#xff0c;开发人员已经转移到他们的下一个任务。为了修复问题&#xff0c;他们必须中断正在做的事情&…

【OpenAI】Python:基于 Gym-CarRacing 的自动驾驶项目(4) | 车辆控制功能的实现

猛戳&#xff01;跟哥们一起玩蛇啊 &#x1f449; 《一起玩蛇》&#x1f40d; ​ &#x1f4ad; 写在前面&#xff1a;本篇是关于多伦多大学自动驾驶专业项目的博客。GYM-Box2D CarRacing 是一种在 OpenAI Gym 平台上开发和比较强化学习算法的模拟环境。它是流行的 Box2D 物…

Faiss PQ 乘积量化

Approximate Nearest Neighbor搜索简称ANN。 从宏观上看ANN brute-force搜索的方式是在全空间进行搜索&#xff0c;为了加快查找的速度&#xff0c;几乎所有的ANN方法都是通过对全空间分割&#xff0c;将其分割成很多小的子空间&#xff0c;在搜索的时候&#xff0c;通过某种…

爬虫分布式爬虫部署知识详解

分布式爬虫是指将一个爬虫任务分解成多个子任务&#xff0c;由多个爬虫节点同时执行&#xff0c;以提高爬取效率和速度的一种爬虫方式。下面是分布式爬虫部署的详细步骤&#xff1a; 确定爬虫任务&#xff1a;首先需要确定要爬取的网站和数据&#xff0c;以及需要爬取的频率和深…

公牛33W车充评测 | 拓尔微 IM2403+TMI3451快充方案实力在线

本期嘉宾是我们的老熟人 公牛PD 33W的车载充电器&#xff0c;此前我们对其进行过拆解&#xff0c;那它的充电表现和各方面性能到底如何呢&#xff1f; 下面我们将围绕协议测试、供电方案和产品测试展开评测解读&#xff0c;帮助小伙伴们全方位了解这款1A1C双口快充车充及相应的…

maven私服搭建详细教程(看完必会)

目录 1 为什么需要私服 2 Nexus私服 2.1 Nexus下载及登录 2.2 maven仓库 2.2.1 代理仓库 2.2.2 宿主仓库 2.2.3 仓库组 3 本地Maven下载构建 3.1 pom.xml方式 3.2 镜像方式 4 本地依赖发布到私服 4.1 maven部署到nexus私服 4.1.1 快照版本 ​4.1.2 release版本 4.2 …

Jar包下载失败的解决方案

Jar包下载失败的解决方案 &#x1f50e;配置阿里源&#x1f50e;重新下载Jar包&#x1f50e;结尾 &#x1f50e;配置阿里源 点击 Settings 搜索 Maven 进行如下修改 注意&#x1f36d; User settings file 路径与 Local repository 路径中应尽量避免出现中文 搜索 User setti…

如何提高高层住宅的消防安全性?安科瑞 许敏

1高层住宅消防安全隐患特点 根据我国对高层住宅的规定&#xff0c;建筑高度大于54m的住宅建筑&#xff08;包括设置商业服务网点的住宅建筑&#xff09;为一类高层住宅建筑&#xff0c;建筑高度大于27m&#xff0c;但不大于54m的住宅建筑&#xff08;包括设置商业服务网点的住宅…

JAVA代码程序如何调用电商API,获取电商数据?

电商API是为了实现各个电商平台之间数据交换而提供的网络接口。Java是一种流行的编程语言&#xff0c;可以通过调用API来获得电商平台提供的各种服务&#xff0c;如商品列表、订单状态等。在这篇文章中&#xff0c;我们将详细介绍如何使用Java代码调用电商API。 1.寻找电商平台…

Python:Proportional Odds Model (POM)序分类比例几率模型

Github上你找不到 Logistic 函数求导看这里

责任链实战场景剖析、以及手写责任链

前言&#xff1a; 最早接触责任链这个设计模式&#xff0c;是我老早前看 Spring Aop 的源码的时候&#xff0c;Aop 的原理是遍历一根按照顺序装载好的 Advice&#xff08;通知&#xff09;拦截器链条&#xff0c;使Before、After 这些 Advice&#xff08;通知&#xff09;中的逻…

Accountill 使用 MongoDB、Express、React 和 Nodejs (MERN) 制作的全栈开源发票应用程序

Accountill 使用 MongoDB、Express、React 和 Nodejs (MERN) 制作的全栈开源发票应用程序。 介绍 使用 MERN 堆栈&#xff08;MongoDB、Express、React 和 Nodejs&#xff09;制作的全栈发票应用程序&#xff0c;专为自由职业者和小型企业设计&#xff0c;几乎可用于任何类型的…

职场中有哪些不成熟的表现

(点击即可收听) 大家好,这里是人人领读,今天给大家分享的,职场中有哪些不成熟的表现,希望能给大家带来一些启发. 1. 不主动汇报自己的工作进度 这个在职场当中,是非常忌讳的,一定要积极反馈,不能闷声憋着,说什么自己社恐,不敢跟上级领导交流,害怕被说 自己被分配的任务做到哪个…

仙人掌之歌——权力的游戏(4)

技术大培训 周一上午&#xff0c;陈速在工位上有些坐立不安&#xff0c;他也不知道自己在等待着什么。脑子里不可遏止地又想起上周五时&#xff0c;易伟成过来找自己说的那些没头没脑的话。易伟成先是询问直播串的参数细节&#xff0c;因为他要设计播放串加密方案&#xff0c;…

大数据架构系列:如何理解湖仓一体?

转载&#xff1a;如有侵权&#xff0c;告知即删除 引言 这十多年大数据技术蓬勃发展&#xff0c;从市场的表现来看基于大数据的数据存储和计算是非常有价值的&#xff0c;其中以云数据仓库为主打业务的公司Snowflake市值最高&#xff08;截止当前449亿美元&#xff09;&#x…

【Spring Cloud】演进与应用的分布式系统开发利器(文末赠书三本)

&#x1f338;作者简介&#xff1a;花想云&#xff0c;目前大二在读 &#xff0c;C/C领域新星创作者、运维领域新星创作者、CSDN2023新星计划导师、CSDN内容合伙人、阿里云专家博主、华为云云享专家 &#x1f338;专栏推荐&#xff1a;C语言初阶系列 、C语言进阶系列 、C系列、…

亚马逊测评养号系统是怎么操作的?

亚马逊鲲鹏测评养号系统可以注册亚马逊买家号、智能一键养号、批量绑定收货地址及支付卡、自动点击广告、货比三家后自动下单、自动留评、QA等&#xff0c;功能非常齐全&#xff0c;基本上是一款从注册到下单于一体的自动化软件。 具体操作流程是先准备好一批账号&#xff08;没…

《SIMD instruction considered harmful》SIMD指令被认为是有害的

作者&#xff1a;大卫帕特森 (David Patterson) 和安德鲁沃特曼 (Andrew Waterman)&#xff0c;2017 年 9 月 18 日 原文链接&#xff1a;SIMD Instructions Considered Harmful | SIGARCH 在撰写 《RISC-V 手册》的过程中&#xff0c;我们将 RISC-V 向量代码与 SIMD 进行了比…

创建一个 vue2.0 的项目(从0到1)的过程

1、首先&#xff1a;下载前端编码工具(如&#xff1a;VSCode) 2、其次&#xff1a;下载 node 与 npm 环境和管理&#xff1a; // 此时就说明成功安装 node 环境与 npm 管理工具&#xff1a; 3、然后&#xff1a;创建全局的 vue (如&#xff1a;vue2.0.8) 和 vue-cli 脚手架; …

Wiki.js 安装 linux(图解)

wiki.js是个开源的知识库系统&#xff0c;官方的docker安装总是出现各种问题&#xff0c; 官方也有给windows的安装包 wiki.js github 一、基础环境 1.nodejs环境 注意&#xff0c;wikijs2.0版本最高支持nodejs16 wikijs3.0支持nodejs18 参考这篇&#xff1a;nodejs编译安装…