Netty01-NIO与BIO

news2024/9/24 1:22:39

NIO

什么是NIO

Java NIO 全称 java non-blocking IO,是指JDK 1.4 及以上版本提供的新API(New IO)。从 JDK1.4 开始,Java 提供了一系列改进的输入/输出的新特性,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供同步非阻塞式的高伸缩性网络。

​ NIO的面向缓冲区和非阻塞I/O模式确实提供了高灵活性和高性能的优势,使得一个线程可以处理多个操作,从而提高了系统的可伸缩性。HTTP/2.0利用了多路复用技术,实现了在同一个连接上并发处理多个请求,相比HTTP/1.1大幅提升了并发请求的效率 .

NIO的三大组件(Channel 通道 , Buffer 缓冲区 ,selector 选择器

NIO原理及浅析_nio原理详解__Kim的博客-CSDN博客

selector 的作用就是配合一个线程来管理多个 channel,获取这些 channel 上发生的事件,这些 channel 工作在非阻塞模式下,当一个channel中没有执行任务时,可以去执行其他channel中的任务。适合连接数多,但流量较少的场景

img

channel

每个channel会对应一个buffer ,每个Buffer其实是一个内存块。

BIO是面向字节流(stream),与Channel的区别在于

  • stream 不会自动缓冲数据,channel 会利用系统提供的发送缓冲区、接收缓冲区(更为底层)
  • stream 仅支持阻塞 API,channel 同时支持阻塞、非阻塞 API,网络 channel 可配合 selector 实现多路复用
  • 二者均为全双工即读写可以同时进行虽然Stream是单向流动的,但是它也是全双工的。

buffer

​ 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装 成 NIO Buffer 对象,并提供了一组方法,用来方便的访问该块内存。缓冲区实际上是 一个容器对象,更直接的说,其实就是一个数组,在 NIO 库中,所有数据都是用缓冲 区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到 缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流 I/O 系统中,所有数据都是直接写入或者直接将数据读取到 Stream 对象中。

buffer的核心属性

  • capacity:缓冲区的容量。通过构造函数赋予,一旦设置,无法更改
  • limit:缓冲区的界限。位于limit 后的数据不可读写。缓冲区的限制不能为负,并且不能大于其容量
  • position下一个读写位置的索引(类似PC)。缓冲区的位置不能为负,并且不能大于limit
  • mark:记录当前position的值。position被改变后,可以通过调用reset() 方法恢复到mark的位置。

以上四个属性必须满足以下要求

mark <= position <= limit <= capacity

buffer的核心方法

put()方法
  • put()方法可以将一个数据放入到缓冲区中。
  • 进行该操作后,postition的值会+1,指向下一个可以放入的位置。capacity = limit ,为缓冲区容量的值

img

flip()方法
  • flip()方法会切换对缓冲区的操作模式,由写->读 / 读->写
  • 进行该操作后
    • 如果是写模式->读模式,position = 0 , limit 指向最后一个元素的下一个位置,capacity不变
    • 如果是读->写,则恢复为put()方法中的值

img

get()方法
  • get()方法会读取缓冲区中的一个值

  • 进行该操作后,position会+1,如果超过了limit则会抛出异常

  • 注意:get(i)方法不会改变position的值

    img

一些IO模型

  • 同步:线程自己去获取结果(一个线程)
    • 例如:线程调用一个方法后,需要等待方法返回结果
  • 异步:线程自己不去获取结果,而是由其它线程返回结果(至少两个线程)
    • 例如:线程A调用一个方法后,继续向下运行,运行结果由线程B返回

当调用一次 channel.read 或 stream.read 后,会由用户态切换至操作系统内核态来完成真正数据读取,而读取又分为两个阶段,分别为:

  • 等待数据阶段
  • 复制数据阶段

img

阻塞IO

img

  • 用户线程进行read操作时,需要等待操作系统执行实际的read操作,此期间用户线程是被阻塞的,无法执行其他操作

非阻塞IO

img

  • 用户线程

    在一个循环中一直调用read方法

    ,若内核空间中还没有数据可读,立即返回

    • 只是在等待阶段非阻塞
  • 用户线程发现内核空间中有数据后,等待内核空间执行复制数据,待复制结束后返回结果

多路复用

img

Java中通过Selector实现多路复用

  • 当没有事件是,调用select方法会被阻塞住
  • 一旦有一个或多个事件发生后,就会处理对应的事件,从而实现多路复用

多路复用与阻塞IO的区别

  • 阻塞IO模式下,若线程因accept事件被阻塞,发生read事件后,仍需等待accept事件执行完成后,才能去处理read事件
  • 多路复用模式下,一个事件发生后,若另一个事件处于阻塞状态,不会影响该事件的执行

异步IO

img

  • 线程1调用方法后理解返回,不会被阻塞也不需要立即获取结果

  • 当方法的运行结果出来以后,由线程2将结果返回给线程1

    零拷贝

    零拷贝指的是数据无需拷贝到 JVM 内存中,同时具有以下三个优点

    • 更少的用户态与内核态的切换
    • 不利用 cpu 计算,减少 cpu 缓存伪共享
    • 零拷贝适合小文件传输

    传统 IO 问题

    img

  • java 本身并不具备 IO 读写能力,因此 read 方法调用后,要从 Java 程序的用户态切换至内核态,去调用操作系统(Kernel)的读能力,将数据读入内核缓冲区。这期间用户线程阻塞,操作系统使用 DMA(Direct Memory Access)来实现文件读,其间也不会使用 CPU

    DMA 也可以理解为硬件单元,用来解放 cpu 完成文件 IO

  • 内核态切换回用户态,将数据从内核缓冲区读入用户缓冲区(即 byte[] buf),这期间 CPU 会参与拷贝,无法利用 DMA

  • 调用 write 方法,这时将数据从用户缓冲区(byte[] buf)写入 socket 缓冲区,CPU 会参与拷贝

  • 接下来要向网卡写数据,这项能力 Java 又不具备,因此又得从用户态切换至内核态,调用操作系统的写能力,使用 DMA 将 socket 缓冲区的数据写入网卡,不会使用 CPU

可以看到中间环节较多,java 的 IO 实际不是物理设备级别的读写,而是缓存的复制,底层的真正读写是操作系统来完成的

  • 用户态与内核态的切换发生了 3 次,这个操作比较重量级
  • 数据拷贝了共 4 次

NIO 优化

通过 DirectByteBuf

  • ByteBuffer.allocate(10)

    • 底层对应 HeapByteBuffer,使用的还是 Java 内存
  • ByteBuffer.

    allocateDirect

    (10)

    • 底层对应DirectByteBuffer,使用的是操作系统内存

img

大部分步骤与优化前相同,唯有一点:Java 可以使用 DirectByteBuffer 将堆外内存映射到 JVM 内存中来直接访问使用

  • 这块内存不受 JVM 垃圾回收的影响,因此内存地址固定,有助于 IO 读写
  • Java 中的 DirectByteBuf 对象仅维护了此内存的虚引用,内存回收分成两步
    • DirectByteBuffer 对象被垃圾回收,将虚引用加入引用队列
      • 当引用的对象ByteBuffer被垃圾回收以后,虚引用对象Cleaner就会被放入引用队列中,然后调用Cleaner的clean方法来释放直接内存
      • DirectByteBuffer 的释放底层调用的是 Unsafe 的 freeMemory 方法
    • 通过专门线程访问引用队列,根据虚引用释放堆外内存
  • 减少了一次数据拷贝,用户态与内核态的切换次数没有减少

进一步优化1

以下两种方式都是零拷贝,即无需将数据拷贝到用户缓冲区中(JVM内存中)

底层采用了 linux 2.1 后提供的 sendFile 方法,Java 中对应着两个 channel 调用 transferTo/transferFrom 方法拷贝数据

img

  • Java 调用 transferTo 方法后,要从 Java 程序的用户态切换至内核态,使用 DMA将数据读入内核缓冲区,不会使用 CPU
  • 数据从内核缓冲区传输到 socket 缓冲区,CPU 会参与拷贝
  • 最后使用 DMA 将 socket 缓冲区的数据写入网卡,不会使用 CPU

这种方法下

  • 只发生了1次用户态与内核态的切换
  • 数据拷贝了 3 次

进一步优化2

linux 2.4 对上述方法再次进行了优化

img

  • Java 调用 transferTo 方法后,要从 Java 程序的用户态切换至内核态,使用 DMA将数据读入内核缓冲区,不会使用 CPU
  • 只会将一些 offset 和 length 信息拷入 socket 缓冲区,几乎无消耗
  • 使用 DMA 将 内核缓冲区的数据写入网卡,不会使用 CPU

整个过程仅只发生了1次用户态与内核态的切换,数据拷贝了 2 次

参考:
黑马程序员netty
Nyima笔记

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

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

相关文章

亲测体验Go语言PGO

本文是对官方 Profile-guided optimization in Go 1.21[1] 的学习与实践. 对于PGO的思路,之前就有过类似的想法,有些许差异. 但本质都是通过对以往运行情况的"学习",优化以后程序的运行(有点以史为鉴和鉴于往事,资于治道的感觉) 过程很简单: 收集程序运行过程中的数据…

zabbix的自动发现机制:

zabbix的自动发现机制: zabbix客户端主动的和服务端联系&#xff0c;将自己的地址和端口发送给服务端&#xff0c;实现自动添加监控主机 客户端是主动的一方 缺点&#xff1b;如果自定义网段中主机数量太多&#xff0c;等级耗时会很久&#xff0c;而且这个自动发现机制不是很…

银河麒麟服务器部署Prometheus+Grafana

#年薪百万# 一、环境准备 操作系统&#xff1a;Operating System: Kylin Linux Advanced Server V10 (Sword) (X86-64) prometheus&#xff1a;prometheus-2.48.0.linux-amd64 grafana&#xff1a;grafana-enterprise-10.2.2.linux-amd64 node_exporter&#xff1a;node_expor…

个体诊所电子处方系统哪个好用,推荐一款可以自由设置配方模板能够填写病历可以查询历史病历的门诊处方笺软件

一、前言 1、功能实用&#xff0c;操作简单&#xff0c;不会电脑也会操作&#xff0c;软件免安装&#xff0c;已内置数据库。 2、中医西医均可用此软件开电子处方&#xff0c;支持病历记录查询&#xff0c;药品进出库管理&#xff0c;支持配方模板一键导入电子处方。 二、电子…

Anaconda创建虚拟环境以及Pycharm和Jupyter如何切换虚拟环境

文章目录 Anaconda创建管理虚拟环境0. 进入到终端1. 创建新环境2. 切换环境3. 删除环境4. 查询当前已有的环境 Pycharm切换虚拟环境0. 更换解析器1. 添加虚拟环境&#xff08;之前默认的是base环境&#xff09;2. 验证切换虚拟环境 Jupyter Notebook 切换虚拟环境1. 安装ipyker…

FPGA串口接收解帧、并逐帧发送有效数据——1

FPGA串口接收解帧、并逐帧发送有效数据 工程实现的功能&#xff1a;FPGA串口接收到串口调试助手发来的数据&#xff0c;将其数据解帧。判断到正确的帧头和帧尾之后&#xff0c;将有效数据存入rx_data中&#xff1b;另一方面发送端将有效数据逐帧发送出去。 参考&#xff1a;正…

嵌入式门槛高吗?

今日话题&#xff0c;嵌入式门槛高吗&#xff1f;在嵌入式领域&#xff0c;门槛因公司和职位的不同而异。普通的嵌入式岗位门槛相对较低&#xff0c;通常要求掌握一些C语言编程和单片机相关知识&#xff0c;可以制作简单的电子产品&#xff0c;但相应的工资较低。然而&#xff…

HNU-电路与电子学-未知年份(不含解析)

【写在前面】 电路与电子学好像是从2020级开设的课程&#xff0c;故实际上目前只有2020与2021两个年级考过期末考试。 这门课程主要由所谓的“数电”与“模电”组成。而且先学的“模电”后学的“”数电&#xff0c;故期中考试主要以“模电”为主&#xff0c;期末考试主要以“…

编译WSL内核,用于操作usb读卡器

wsl2默认不能操作usb读卡器&#xff0c;但是对于嵌入式linux开发来说&#xff0c;需要经常对tf卡进行操作&#xff0c;随时都会使用到usb读卡器的访问。下面讲述如何开启wsl2的usb读卡器的访问&#xff0c;主要涉及到以下2个步骤&#xff1a; wsl2本质是一个虚拟机&#xff0c…

【GO】protobuf在golang中的测试用例

上篇文章介绍了如何安装protobuf环境&#xff0c;文章链接如下 【Go】protobuf介绍及安装-CSDN博客 本节介绍protobuf在gRPC中具体如何使用&#xff0c;并编写测试用例 一、Protobuf是如何工作的 .proto文件是protobuf一个重要的文件&#xff0c;它定义了需要序列化数据的结…

Ubuntu 20.0 + mysql 8.0 用户和密码修改

第一步 下载&#xff08;简单,注意联网&#xff09;Ubuntu 终端输入以下两行命令 (1) 数据库的服务端及客户端数据库的开发软件包 sudo apt-get install mysql-server mysql-client (2) 数据库的开发软件包 sudo apt-get install libmysqlclient-dev 第二步 查看是否安装成功 …

深度分析电动工具的发展趋势,盘点几个极具潜力的科技功能点

纵观市场发展规律&#xff0c;人类的每一次能源转型&#xff0c;都会带来大量红利商机&#xff0c;也会催生整个产业链的彻底革新。 一、电动工具的惊人爆发力 比如说电动工具这个大品类&#xff0c;在近两年意想不到地成为全球隐形增长冠军。主要原因在于海外市场有大量 DIY…

HNU-电路与电子学-2019期末A卷(不含解析)

【写在前面】 电路与电子学好像是从2020级开设的课程&#xff0c;故实际上目前只有2020与2021两个年级考过期末考试。 这门课程主要由所谓的“数电”与“模电”组成。而且先学的“模电”后学的“”数电&#xff0c;故期中考试主要以“模电”为主&#xff0c;期末考试主要以“数…

持续集成交付CICD:GitLab Webhook触发Jenkins流水线

目录 一、实验 1.Jenkins远程下载GiaLab仓库代码 2.curl远程触发Jenkins流水线 3.GitLab Webhook触发Jenkins流水线 二、问题 1.GitLab配置Webhook时报错 一、实验 1.Jenkins远程下载GiaLab仓库代码 (1) Jenkins添加选项参数 (2)添加字符参数 (3)查看构建参数情况 (4)添…

孩子都能学会的FPGA:第二十一课——用线性反馈移位寄存器实现伪随机序列

&#xff08;原创声明&#xff1a;该文是作者的原创&#xff0c;面向对象是FPGA入门者&#xff0c;后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门&#xff0c;作者不光让大家知其然&#xff0c;还要让大家知其所以然&#xff01;每个工程作者都搭建了全自动化的仿…

神经网络常用归一化和正则化方法解析(一)

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

CRM:提升营销效果的关键

一场成功的营销活动&#xff0c;可以帮助企业扩大知名度&#xff0c;获取大量的优质商机。作为专业的管理软件&#xff0c;CRM系统同样具备营销管理的能力&#xff0c;帮助企业实现营销活动的规划、执行和监控&#xff0c;提高营销效果。下面说说&#xff0c;CRM营销自动化对企…

职场人的年底总结,年初规划,又要开始啦!

在2023年&#xff0c;你可能错过了某些重要的职业发展机会&#xff0c;或者错失了一些与家人和朋友共度的时光。也可能经历了企业的降本增效&#xff0c;面临了被否定和裁员的风险&#xff1b;或者是得到了企业的重用和提拔&#xff0c;一个人撑起了整个业务部门。这些经历不仅…

Python中函数添加超时时间,Python中signal使用

from time import time, sleepimport signal# 模拟要删除5条数据,中间有超时的i 5# 超时后执行的方法def timeout_handler(signal, frame):# 引发异常raise TimeoutError("删除第" str(i) "条,超时!")# 或者执行其他操作,不往外抛异常(超时的函数不会被…

【排障记录】Oracle自动归档清理任务无法进行(windows平台),原因居然是?

前言 接用户求助&#xff0c;生产业务上的一套数据库存在归档文件占用过多磁盘空间的问题&#xff08;约四万个&#xff09;&#xff0c;需要清理&#xff0c;最好设置成定期自动清理&#xff0c;以减少人工干预。 处置过程 由于Oracle搭建在windows操作系统之上&#xff0c…