详解Java中的五种IO模型

news2024/12/25 2:28:26

文章目录

  • 前言
    • 1、内核空间和用户空间
    • 2、用户态和内核态
    • 3、上下文切换
    • 4、虚拟内存
    • 5、DMA技术
    • 6、传统 IO 的执行流程
  • 一、阻塞IO模型
  • 二、非阻塞IO模型
  • 三、IO多路复用模型
    • 1、IO多路复用之select
    • 2、IO多路复用之epoll
    • 3、总结select、poll、epoll的区别
  • 四、IO模型之信号驱动模型
  • 五、IO 模型之异步IO(AIO)
  • 总结

前言

  • 在学习IO模型前,需要先了解些基础概念,才能理解IO的执行流程及阻塞的原因

1、内核空间和用户空间

  我们电脑上跑着的应用程序,其实是需要经过操作系统,才能做一些特殊操作,如磁盘文件读写、内存的读写等等。因为这些都是比较危险的操作,不可以由应用程序乱来,只能交给底层操作系统来。

  因此,操作系统为每个进程都分配了内存空间,一部分是用户空间,一部分是内核空间。内核空间是操作系统内核访问的区域,是受保护的内存空间,而用户空间是用户应用程序访问的内存区域。

  • 内核空间:主要提供进程调度、内存分配、连接硬件资源等功能
  • 用户空间:提供给各个程序进程的空间,它不具有访问内核空间资源的权限
    • 如果应用程序需要使用到内核空间的资源,则需要通过系统调用来完成
    • 进程从用户空间切换到内核空间,完成相关操作后,再从内核空间切换回用户空间

  我们应用程序是跑在用户空间的,它不存在实质的IO过程,真正的IO是在操作系统执行的。即应用程序的IO操作分为两种动作:IO调用和IO执行。IO调用是由进程(应用程序的运行态)发起,而IO执行是操作系统内核的工作。此时所说的IO是应用程序对操作系统IO功能的一次触发,即IO调用。

2、用户态和内核态

  • 如果进程运行于内核空间,被称为进程的内核态
  • 如果进程运行于用户空间,被称为进程的用户态

3、上下文切换

  CPU寄存器,是CPU内置的容量小、但速度极快的内存。而程序计数器,则是用来存储 CPU正在执行的指令位置、或者即将执行的下一条指令位置。它们都是CPU在运行任何任务前,必须的依赖环境,因此叫做CPU上下文。

  CPU上下文切换就是先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

  一般我们说的上下文切换,就是指内核(操作系统的核心)在CPU上对进程或者线程进行切换。进程从用户态到内核态的转变,需要通过系统调用来完成。系统调用的过程,会发生CPU上下文的切换。

在这里插入图片描述

4、虚拟内存

  • 现代操作系统使用虚拟内存,即虚拟地址取代物理地址,使用虚拟内存可以有2个好处:
    • 虚拟内存空间可以远远大于物理内存空间
    • 多个虚拟内存可以指向同一个物理地址

  正是多个虚拟内存可以指向同一个物理地址,可以把内核空间和用户空间的虚拟地址映射到同一个物理地址,这样的话,就可以减少IO的数据拷贝次数啦。

在这里插入图片描述

5、DMA技术

  DMA,英文全称是Direct Memory Access,即直接内存访问。DMA本质上是一块主板上独立的芯片,允许外设设备和内存存储器之间直接进行IO数据传输,其过程不需要CPU的参与

在这里插入图片描述

  1. 用户应用进程调用read函数,向操作系统发起IO调用,进入阻塞状态,等待数据返回
  2. CPU收到指令后,对DMA控制器发起指令调度
  3. DMA收到IO请求后,将请求发送给磁盘
  4. 磁盘将数据放入磁盘控制缓冲区,并通知DMA
  5. DMA将数据从磁盘控制器缓冲区拷贝到内核缓冲区
  6. DMA向CPU发出数据读完的信号,把工作交换给CPU,由CPU负责将数据从内核缓冲区拷贝到用户缓冲区
  7. 用户应用进程由内核态切换回用户态,解除阻塞状态

  DMA的主要作用就是将数据从磁盘拷贝到内核缓冲区,这期间可以解放CUP去做其他事。

6、传统 IO 的执行流程

  • 传统的IO流程,包括read和write的过程
    • read:把数据从磁盘读取到内核缓冲区,再拷贝到用户缓冲区
    • write:先把数据写入到socket缓冲区,最后写入网卡设备

流程图如下:
在这里插入图片描述

读数据

  • 用户应用进程调用read函数,向操作系统发起IO调用,上下文从用户态转为內核态(切换1)
  • DMA控制器把数据从磁盘中,读取到内核缓冲区
  • CPU把内核缓冲区数据,拷贝到用户应用缓冲区,上下文从内核态转为用户态(切换2),read函数返回

写数据

  • 用户应用进程通过write函数,发起IO调用,上下文从用户态转为内校态(切换3)
  • CPU将应用缓冲区中的数据,拷贝到socket缓冲区
  • DMA控制器把数据从socket缓冲区,拷贝到网卡设备,上下文从内校态切换回用户态(切换4),write函数返回

  从流程图可以看出,传统IO的读写流程,包括了4次上下文切换(4次用户态和内核态的切换),4次数据拷贝(两次CPU拷贝以及两次的DMA拷贝)。

一、阻塞IO模型

  应用程序的进程发起IO调用,但是如果内核的数据还没准备好的话,那应用程序进程就一直在阻塞等待,一直等到内核数据准备好了,从内核拷贝到用户空间,才返回成功提示,此次IO操作,称之为阻塞IO

在这里插入图片描述

  • 阻塞IO比较经典的应用就是阻塞socketJava BIO
  • 阻塞IO的缺点就是:如果内核数据一直没准备好,那用户进程将一直阻塞,浪费性能,可以使用非阻塞IO优化

二、非阻塞IO模型

  如果内核数据还没准备好,系统调用会立即返回一个调用失败的信息,让它不需要等待,而是通过轮询的方式再来请求。如果内核数据准备好,在数据从内核拷贝到用户空间期间是阻塞的(因为现在是CUP在操作,之前准备数据是DMA)。

在这里插入图片描述

  • 同步非阻塞 IO 的优点是每次发起的IO系统调用在内核等待数据过程中可以立即返回,用户线程不会阻塞,实时性较好
  • 同步非阻塞IO的缺点是不断地轮询内核,这将占用大量的CPU时间,效率低下

三、IO多路复用模型

  在这之前,我们先来复习下,什么是文件描述符fd(File Descriptor),它是计算机科学中的一个术语,形式上是一个非负整数。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。

  IO复用模型核心思路:系统给我们提供一类函数(如我们耳濡目染的selectpollepoll函数),它们可以同时监控多个fd的操作,任何一个返回内核数据就绪,应用进程再发起recvfrom系统调用。

1、IO多路复用之select

  应用进程通过调用select函数,可以同时监控多个fd,在select函数监控的fd中,只要有任何一个数据状态准备就绪了,select函数就会返回可读状态,这时应用进程再发起recvfrom请求去读取数据。

  非阻塞IO模型(NIO)中,需要N(N>=1)次轮询系统调用,然而借助select的IO多路复用模型,只需要发起一次询问就够了,大大优化了性能。

在这里插入图片描述

select缺点

  • 监听的IO最大连接数有限,在Linux系统上一般为1024
  • select函数返回后,是通过遍历fdset,找到就绪的描述符fd。(仅知道有I/O事件发生,却不知是哪几个流,所以遍历所有流)

  因为存在连接数限制,所以后来又提出了poll。与select相比,poll解决了连接数限制问题。但是呢,select和poll一样,还是需要通过遍历文件描述符来获取已经就绪的socket。如果同时连接的大量客户端,在一时刻可能只有极少处于就绪状态,伴随着监视的描述符数量的增长,效率也会线性下降。因此经典的多路复用模型epoll诞生。

2、IO多路复用之epoll

  为了解决select/poll存在的问题,多路复用模型epoll诞生,它采用事件驱动来实现。

在这里插入图片描述

  epoll先通过epoll_ctl()来注册一个fd(文件描述符),一旦基于某个fd就绪时,内核会采用回调机制,迅速激活这个fd,当进程调用epoll_wait()时便得到通知。这里去掉遍历文件描述符的操作,而是采用监听事件回调的机制。这就是epoll的亮点。

3、总结select、poll、epoll的区别

selectpollepoll
底层数据结构数组链表红黑树和双链表
获取就绪的fd遍历遍历事件回调
事件复杂度O(n)O(n)O(1)
最大连接数1024无限制无限制
fd数据拷贝每次调用select,需要将fd数据从用户空间拷贝到内核空间每次调用poll,需要将fd数据从用户空间拷贝到内核空间使用内存映射(mmap),不需要从用户空间频繁拷贝fd数据到内核空间

  epoll明显优化了IO的执行效率,但在进程调用epoll_wait()时,仍然可能被阻塞。能不能酱紫:不用我老是去问你数据是否准备就绪,等我发出请求后,你数据准备好了通知我就行了,这就诞生了信号驱动IO模型。

四、IO模型之信号驱动模型

  信号驱动IO不再用主动询问的方式去确认数据是否就绪,而是向内核发送一个信号(调用sigaction的时候建立一个SIGIO的信号),然后应用用户进程可以去做别的事,不用阻塞。当内核数据准备好后,再通过SIGIO信号通知应用进程,数据准备好后的可读状态。应用用户进程收到信号之后,立即调用recvfrom,去读取数据。

在这里插入图片描述

  信号驱动IO模型,在应用进程发出信号后,是立即返回的,不会阻塞进程。它已经有异步操作的感觉了。但是你细看上面的流程图,发现数据复制到应用缓冲的时候,应用进程还是阻塞的。回过头来看下,不管是BIO,还是NIO,还是信号驱动,在数据从内核复制到应用缓冲的时候,都是阻塞的。还有没有优化方案呢?AIO(真正的异步IO)

五、IO 模型之异步IO(AIO)

  AIO也就是NIO2。Java7中引入了NIO的改进版NIO2,它是异步IO模型

在这里插入图片描述

AIO 用来解决数据复制阶段的阻塞问题

  • 同步意味着,在进行读写操作时,线程需要等待结果,还是相当于闲置
  • 异步意味着,在进行读写操作时,线程不必等待结果,而是将来由操作系统来通过回调方式由另外的线程来获得结果

总结

阻塞、非阻塞、同步、异步IO划分

在这里插入图片描述

BIO、NIO、AIO

  • 同步阻塞(blocking-IO)简称BIO
  • 同步非阻塞(non-blocking-IO)简称NIO
  • 异步非阻塞(asynchronous-non-blocking-IO)简称AIO

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

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

相关文章

Git 原理及使用 (带动图演示)

文章目录 🌈 Ⅰ Git 安装🌙 01. Linux - centos 🌈 Ⅱ Git 工作区、暂存区和版本库🌙 01. 认识工作区、暂存区和版本库🌙 02. 使用 Git 管理工作区的文件 🌈 Ⅲ Git 基本操作🌙 01. 创建本地仓库…

Java代码基础算法练习-斐波纳契数列-2024.04.22

任务描述: 1,1,2,3,5,8,13,21,34,55,89……这个数列则称为“斐波那契数列”,其中每 个数字都是“斐波那契数”。 输入一个整数N(N不大…

服务器渲染技术(JSPELJSTL)

目录 前言 一.JSP 1.基本介绍 3.page指令(常用) 4.JSP三种常用脚本 4.1 声明脚本 <%! code %> 4.2 表达式脚本 <% code %> 4.3 代码脚本 <% code %> 4.4 注释 <%-- 注释 --%> 5. JSP 内置对象 5.1 基本介绍 5.2 九个内置对象 6.JSP域对象 二…

4-内核开发-第一个块设备模块开发案例

4-内核开发-第一个块设备模块开发案例 目录 4-内核开发-第一个块设备模块开发案例 1.开发原则创建步骤 2. 编译并加载模块 ​3.安装模块 4.检查模块是否加载成功 5.通过设备名称查看 6. 创建一个块设备文件 7. 查看块设备 8.模块卸载 9.总结 课程简介&#xff1a; L…

Qt-饼图示范

1.效果图 2.代码如下 2.1 .h文件 #ifndef PIECHARTWIDGET_H #define PIECHARTWIDGET_H#include <QWidget> #include <QChartView> #include <QPieSeries>#include<QVBoxLayout> #include<QMessageBox> #include <QtCharts>struct PieDat…

电子印章盖骑缝章

电子印章盖骑缝章是指在电子文档&#xff08;如PDF文件&#xff09;中&#xff0c;使用电子印章技术&#xff0c;为文档添加一个跨越多页、连续显示的电子印章图像&#xff0c;以模拟传统纸质文档上的骑缝章效果。以下是实现电子印章盖骑缝章的步骤&#xff1a; 一. 准备电子印…

linux休眠唤醒流程,及示例分析

休眠流程 应用层通过echo mem > /sys/power/state写入休眠状态&#xff0c;给一张大概流程图 这个操作对应在kernel/power/main.c的state这个attr的store操作 static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n) …

Linux - Docker 安装 Nacos

拉取 Nacos 镜像 使用以下命令从 Docker Hub 拉取最新版本的 Nacos 镜像&#xff1a; docker pull nacos/nacos-server启动 Nacos 容器 使用以下命令启动 Nacos 容器&#xff1a; docker run -d \--name nacos \--privileged \--cgroupns host \--env JVM_XMX256m \--env M…

【Harmony3.1/4.0】笔记三

概念 网格布局是由“行”和“列”分割的单元格所组成&#xff0c;通过指定“项目”所在的单元格做出各种各样的布局。网格布局具有较强的页面均分能力&#xff0c;子组件占比控制能力&#xff0c;是一种重要自适应布局&#xff0c;其使用场景有九宫格图片展示、日历、计算器等…

Vue2 —— 学习(十)

一、vue-resource 库 了解即可 在之前的 vue 版本中经常使用 这个库发送 ajax 请求 现在建议使用 axios 我们可以通过使用 vue-resource 库 来实现发送 ajax 请求 它是 vue 的一个插件库 Vue.use() 就能使用我们的插件了 我们引入后去 我们的实例对象 vc 中查看 发现出现…

设计模式之访问者模式(下)

3&#xff09;访问者模式与组合模式联用 1.概述 在访问者模式中&#xff0c;包含一个用于存储元素对象集合的对象结构&#xff0c;可以使用迭代器来遍历对象结构&#xff0c;同时具体元素之间可以存在整体与部分关系&#xff0c;有些元素作为容器对象&#xff0c;有些元素作为…

2024年小程序视频下载教程

现在已经是2024年&#xff0c;还是有很多人不知道如何下载小程序视频&#xff0c;这里就教大家如何下载小程序视频&#xff0c;一共有3种方法 1.录屏 2.利用抓包工具(Fiddler&Charles) 3.利用专门的下载资源工具(下载高手) 我介绍其中的第3种方法 工具我已经打包好了 …

【Linux学习】Linux调试器-gdb使用

这里写目录标题 &#x1f302;背景&#x1f302;gdb使用&#x1f302;指令总结&#xff1a; &#x1f302;背景 程序的发布方式有两种&#xff0c;debug模式和 release模式 其中&#xff0c;debug模式是可以被调试的&#xff0c;到那时release模式是不能被调试的&#xff1b; …

股东减持,营收“四连降”,三只松鼠用什么撑起“百亿”野心?

近日&#xff0c;国内零食品牌三只松鼠&#xff08;SZ:300783&#xff09;发布了2023年业绩报告。从规模效益的层面出发&#xff0c;三只松鼠在高端化和高性价比逻辑下对门店进行了集中优化&#xff0c;虽然营收略有下降&#xff0c;但利润端却实现了强势回暖。 不过&#xff…

表达式求值(后缀表达式)(数据结构)

一、概念 算术表达式是由操作数&#xff08;运算数&#xff09;、运算符&#xff08;操作符&#xff09;、和界线符&#xff08;括号&#xff09;三部分组成&#xff0c;在计算机中进行算术表达式的计算是通过堆栈来实现的。 二后缀表达式的逻辑和实现方式&#xff08;逆波兰…

4*5的矩阵(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i 0;int j 0;int result 0;//嵌套循环输出&#xff1b;for (i 1; i < 4; i){//列…

冯喜运:4.22黄金蒋继续“消化超买“,原油回落,通胀担忧缓解?

【 黄金消息面解析】&#xff1a;上周五(4月19日)伊朗媒体似乎淡化了以色列袭击的影响&#xff0c;表明地缘政治风险降低&#xff0c;导致避险资产需求放缓&#xff0c;金价回吐涨幅。上周现货黄金价格上涨超2%。美国黄金期货收盘上涨0.7%&#xff0c;至2413.8美元。从长期来看…

前端开发攻略---合并表格单元格,表格内嵌套表格实现手风琴效果。

1、演示 2、思路 1、用传统的 <table></table> 表格标签来实现比较麻烦。因此通过模拟 表格标签 的写法用<div></div>来实现 2、表头和表格列数是相同的&#xff0c;因此可以确定代码结构 <div class"table"><div class"head…

【Linux 进程间通信】管道(三)

文章目录 1.管道的五种特征2.管道的四种情况 1.管道的五种特征 ①&#x1f34e;匿名管道只能用于有血缘关系的进程之间进行通信&#xff08;爷孙进程之间可以进行通信&#xff09;&#xff0c;常用于父子之间进行通信&#xff1b; ②&#x1f34e;管道内部&#xff0c;自带进…

Mysql的【存储引擎】之【InnoDB】与【MyISAM】的区别

目录 1.存储引擎在 MyISAM 和 InnoDB 有什么区别 2.Mysql 5.7 默认的存储引擎是什么 3.一个简单例子&#xff08;如果非要使用【MyISAM】存储引擎 &#xff09; 4.2009年写的留言板程序的数据&#xff08;存储引擎是&#xff1a;【MyISAM】&#xff09; 5.mysql 8.0 可以使…