Java基础--->IO流(2)【常见IO模型】

news2024/12/22 19:14:45

文章目录

  • 计算机角度IO
  • 操作系统IO
  • 常见的IO模型
  • Java 中 3 种常见 IO 模型
    • BIO(BlockingI/O)【同步阻塞IO】
    • NIO(Non-blocking/New I/O)【非阻塞IO】
    • IO多路复用
    • AIO(Asynchronous I/O)【异步IO】

计算机角度IO

根据冯.诺依曼结构,计算机结构分为 5 大部分:运算器、控制器、存储器、输入设备、输出设备。

在这里插入图片描述

从计算机结构的视角来看的话, I/O 描述了计算机系统与外部设备之间通信的过程。

IO (Input/Output) 通常是指计算机与外部设备之间的数据交换过程。输入设备(如键盘、鼠标、摄像头等)把数据输入到计算机中,输出设备(如显示器、打印机、扬声器等)把数据从计算机中输出。

输入设备向计算机输入数据,输出设备接收计算机输出的数据。

我们再先从应用程序的角度来解读一下 I/O。

为了保证操作系统的稳定性和安全性,一个进程的地址空间划分为 用户空间(User space)内核空间(Kernel space )

像我们平常运行的应用程序都是运行在用户空间,只有内核空间才能进行系统态级别的资源有关的操作,比如文件管理、进程通信、内存管理等等。也就是说,我们想要进行 IO 操作,一定是要依赖内核空间的能力。

并且,用户空间的程序不能直接访问内核空间。

当想要执行 IO 操作时,由于没有执行这些操作的权限,只能发起系统调用请求操作系统帮忙完成。

因此,用户进程想要执行 IO 操作的话,必须通过 系统调用 来间接访问内核空间

操作系统IO

从操作系统角度来看,IO是指操作系统通过设备驱动程序与硬件设备进行数据交换的过程。操作系统通过系统调用、中断等机制控制IO操作,进而实现数据的输入和输出。操作系统通过各种设备驱动程序来管理硬件设备,使得应用程序可以方便地对设备进行访问,并获得所需的输入输出数据。

在计算机中,IO是所有操作中最耗时的一部分,因为设备的存储和处理速度比主存储器和CPU低得多。所以,为了缩短IO的响应时间,操作系统通常会使用缓存技术,将提前读取或写出的数据缓存到内存里,加快后续访问的速度。此外,操作系统还会针对不同类型的设备使用不同的IO调度算法,以提高整体IO效率,例如 FCFS(先来先服务)、SJF(最短作业优先)、CFQ(完全公平调度算法)等。

操作系统负责计算机的资源管理和进程的调度,我们电脑上跑着的应用程序,其实是需要经过操作系统,才能做一些特殊操作,如磁盘文件读写、内存的读写等。真正的 IO 是在操作系统执行的。即应用程序的 IO 操作分为两种动作:IO 调用 和 IO 执行。IO 调用是由进程(应用程序的运行态)发起,而 IO 执行是操作系统内核的工作。

应用程序发起的一次 IO 操作包含两个阶段:

IO 调用:应用程序进程向操作系统内核发起调用。

IO 执行:操作系统内核完成 IO 操作。

​ 真正的IO都是操作系统执行的,应用程序IO一般两种:IO调用和IO执行

​ 看似Java在读,实际是操作系统在读

常见的IO模型

UNIX 系统下, IO 模型一共有 5 种:同步阻塞 I/O同步非阻塞 I/OI/O 多路复用信号驱动 I/O异步 I/O

Java 中 3 种常见 IO 模型

BIO(BlockingI/O)【同步阻塞IO】

在这里插入图片描述

阻塞IO模型也称为同步IO模型,在这种模型中,一个线程需要在所有IO操作完成之后才能继续执行后续的代码,因此也被称为“同步”模型。在阻塞IO模型中,当一个线程调用了read()或write()等IO操作时,线程会一直等待,直到操作系统完成IO操作并返回结果,才会继续执行后续的代码。

同步阻塞 IO 模型中,应用程序发起 read 调用后,会一直阻塞,直到内核把数据拷贝到用户空间。

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

Java之前所学的IO都是阻塞式IO。

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

NIO(Non-blocking/New I/O)【非阻塞IO】

在这里插入图片描述

非阻塞IO模型也称为异步IO模型,在这种模型中,一个线程可以发起IO请求后立即返回,而不需要等待IO操作的结果,因此也被称为“异步”模型。在非阻塞IO模型中,当一个线程调用了read()或write()等IO操作时,线程不会等待操作系统返回结果,而是继续执行后续的代码。当操作系统完成IO操作后,它会通知应用程序,告知IO操作的结果。

如果内核数据还没准备好,可以先返回错误信息给用户进程,让它不需要等待,而是通过轮询的方式再来请求。这就是非阻塞 IO

同步非阻塞 IO 模型中,应用程序会一直发起 read 调用,等待数据从内核空间拷贝到用户空间的这段时间里,线程依然是阻塞的,直到在内核把数据拷贝到用户空间。

相比于同步阻塞 IO 模型,同步非阻塞 IO 模型确实有了很大改进。通过轮询操作,避免了一直阻塞。

但是,这种 IO 模型同样存在问题:应用程序不断进行 I/O 系统调用轮询数据是否已经准备好的过程是十分消耗 CPU 资源的。

这个时候,I/O 多路复用模型 就出现了

IO多路复用

在这里插入图片描述

IO 多路复用模型中,线程首先发起 select 调用,询问内核数据是否准备就绪,等内核把数据准备好了,用户线程再发起 read 调用。read 调用的过程(数据从内核空间 -> 用户空间)还是阻塞的。发起请求数据时,操作系统立即返回一个结果(不是数据),等数据完全准备好了,向用户进程进行响应。

IO 多路复用模型,通过减少无效的系统调用,减少了对 CPU 资源的消耗。

既然 NIO 无效的轮询会导致 CPU 资源消耗,我们等到内核数据准备好了,主动通知应用进程再去进行系统调用。

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

文件描述符 fd(File Descriptor),它是计算机科学中的一个术语,形式上是一个非负整数。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。

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

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

缺点:监听的 IO 最大连接数有限,在 Linux 系统上一般为 1024。select 函数返回后,是通过遍历 fdset,找到就绪的描述符 fd。(仅知道有 I/O 事件发生,却不知是哪几个流,所以遍历所有流). 因为存在连接数限制,所以后来又提出了poll。与 select 相比,poll 解决了连接数限制问题。但是,select 和 poll 一样,还是需要通过遍历文件描述符来获取已经就绪的 socket。如果同时连接的大量客户端,在一时刻可能只有极少处于就绪状态,伴随着监视的描述符数量的增长,效率也会线性下降

因此出现了epoll

epoll: 为了解决 select/poll 存在的问题,多路复用模型 epoll 诞生,它采用事件驱动来实现。epoll 先通过 epoll_ctl()来注册一个 fd(文件描述符),一旦基于某个 fd 就绪时,内核会采用回调机制,迅速激活这个 fd,当进程调用 epoll_wait()时便得到通知。这里去掉了遍历文件描述符的坑爹操作,而是采用监听事件回调的机制。这就是 epoll 的亮点。

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

IO 模型之信号驱动模型

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

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

AIO(Asynchronous I/O)【异步IO】

在这里插入图片描述

前面讲的 BIO,NIO 和信号驱动,在数据从内核复制到应用缓冲的时候,都是阻塞的,因此都不算是真正的异步。AIO 实现了 IO 全流程的非阻塞,就是 应用进程发出系统调用后,是立即返回的,但是立即返回的不是处理结果,而是表示提交成功类似的意思。等内核数据准备好,将数据拷贝到用户进程缓冲区,发送信号通知用户进程 IO 操作执行完毕。

大概总结一下是这样

在这里插入图片描述

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

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

相关文章

进攻中型SUV,蔚来/小鹏的智能化「满配」能否撬动需求

251.29万辆,这是2022年中国市场(不含进出口)乘用车中型SUV交出的答卷,交付量仅次于紧凑型SUV,排名细分市场第二。在这份成绩单中,有几个数字特别醒目。 1、31.64万辆,这是排名这个细分市场交付量…

chatgpt赋能python:Python交易股票:掌握交易技巧,开启财富增长之路

Python 交易股票:掌握交易技巧,开启财富增长之路 股票市场一直以来都是吸引人们收益的地方,不断变化的市场行情也让每一位投资者都不得不面对各种风险。然而,如果您懂得运用好 Python 来交易股票,就能够更好地理解市场…

【软考-中级】系统集成项目管理工程师 【14 采购管理】

持续更新。。。。。。。。。。。。。。。 【第十四章】采购管理 2 分 14.1采购管理的相关概念和主要过程14.1.1 概念和术语14.1.2 采购管理的主要过程 14.2编制采购管理计划14.2.1编制采购计划的输入、输出14.2.2用于编制采购计划过程的技术和方法14.2.3工作说明书 历年真题202…

小程序外包开发上线流程

小程序有非常多的优势,无需下载安装、使用方便、开发成本低、覆盖广泛、轻量级、方便推广,这些特点使得小程序非常适合场景不太复杂的场合,这些年出现了大量的小程序。今天和大家分享一下小程序的一些特点和上线流程,希望对大家有…

C#,码海拾贝(21)——“全选主元高斯消去法“求解“线性方程组“的C#源代码,《C#数值计算算法编程》源代码升级改进版

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static class LEquations { /// <summary> /…

mysql倒库操作遇到的问题

背景&#xff1a;本地windows 10安装了mysql数据库后&#xff0c;需要把远程库的表结构和数据全部导入进来。 操作&#xff1a;导出数据库&#xff0c;导入数据库。 第一步&#xff1a;导出数据库 使用dump命令即可。 登陆mysql数据库 mysql -hhost --default-character-s…

springboot整合ueditor有源码

在项目用到ueditor插件来编辑信息&#xff0c;初次接触&#xff0c;遇到各种问题&#xff0c;到目前为止&#xff0c;也只是基本实现了功能&#xff0c;简单记录一下过程&#xff0c;希望对初次使用ueditor的朋友们有所帮助。 ueditor就不介绍了&#xff0c;或对ueditor还不了…

尝试 python flink

引入pyflink库 启动anaconda的终端窗口 执行命令 pip install apache-flink1.13.2 等待安装flink相关库

< ElementUi组件库: el-progress 进度条Bug及样式调整 >

ElementUi组件库&#xff1a; el-progress 进度条Bug及样式调整 &#x1f449; 前言&#x1f449; 一、实现原理> 修改 el-progress 进度条样式 及 渐变进度条样式 &#x1f449; 二、案例代码&#xff08;前言效果图案例&#xff09;> HTML代码> CSS代码 &#x1f44…

详细解读Diffuser DreamBooth代码

Diffusion Models专栏文章汇总:入门与实战 前言:之前的博客《如何定制属于自己的stable diffusion?Dreambooth原理详解和代码实战》详细解读了dreambooth,不过那篇博客的代码讲解部分主要基于mmagic,不过瘾。这篇博客讲解一下diffuser的drembooth的部分。 目录 参数详解…

C#,码海拾贝(24)——求解“复系数方程组”的“全选主元高斯-约当消去法”之C#源代码,《C#数值计算算法编程》源代码升级改进版

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static partial class LEquations { /// <summary> …

Ansible从入门到精通【一】

大家好&#xff0c;我是早九晚十二&#xff0c;目前是做运维相关的工作。写博客是为了积累&#xff0c;希望大家一起进步&#xff01; 我的主页&#xff1a;早九晚十二 专栏名称&#xff1a;Ansible从入门到精通 立志成为ansible大佬 Ansible初识 ansible基于Python开发&#…

关闭linux kernel内核的启动log在控制台的输出

要关闭Linux内核的启动日志&#xff0c;你可以通过以下方法之一进行操作&#xff1a; 1. 通过引导加载器配置&#xff1a; 打开引导加载器的配置文件&#xff0c;如GRUB的配置文件 /boot/grub/grub.cfg。 在内核的启动行&#xff08;以 “linux” 或 “kernel” 开头&#xf…

MyBatisPlus快速入门(二)MyBatisPlus快速入门体验

一、初始化数据库&#xff08;基于 HeidiSQL&#xff09;1.1 创建数据库1.2创建数据表1.3 初始化数据 二、初始化项目&#xff08;基于Spring Boot&#xff09;2.1 创建项目2.2 新增依赖2.3 数据库配置2.4 配置 MyBatis Plus2.5 创建实体类2.6 创建Mapper层接口2.7 创建Server层…

怎么用迅捷PDF转换器在线修改图片大小

大家在生活和工作中会遇到图片的大小尺寸不合适的情况&#xff0c;尤其是一些公用的照片&#xff0c;都会有固定的尺寸要求。或者是一些同学想要考研考公考编之类的&#xff0c;也需要严格按照规定来修改图片。那么怎么才能快速修改图片大小呢&#xff1f; 推荐大家使用迅捷PD…

OpenVINO 2022.3实战四:POT API 实现 YOLOv5 模型 INT8 量化

OpenVINO 2022.3实战四&#xff1a;POT API 实现 YOLOv5 模型 INT8 量化 将预训练的 YOLOv5m Pytorch 模型转换为 OpenVINO™ FP32 Intermediate Representation (IR) 模型。下一步&#xff0c;通过 OpenVINO™ Post-Training Optimization Tool (POT) API 来定义客制化DataLo…

Linux之文件权限类命令

文件权限类命令 文件属性 Linux系统是一种典型的多用户系统&#xff0c;不同的用户处于不同的地位&#xff0c;拥有不同的权限。为了保护系统的安全线&#xff0c;Linux系统对不同的用户访问同一文件&#xff08;包括目录文件&#xff09;的权限做了不同的规定&#xff0c;在…

白嫖免费版gpt与wetab插件的使用

目录 网址 如何使用 wetab 介绍wetab 怎么获得这个插件 使用效果 网址 1. wetab网站 : chatgpt (免费&#xff0c;不需要账号&#xff0c;不需要翻墙) 2. gpt镜像网站&#xff1a;https://chatbot.theb.ai/#/chat/1002 &#xff08;免费&#xff0c;不需要账号&#xff0…

learn C++ NO.6——类和对象(4)

1.再谈构造函数 1.1.构造函数体赋值 在创建类的对象时&#xff0c;编译器回去调用类的构造函数&#xff0c;来各个成员变量一个合适的值。 class Date { public:Date(int year,int month,int day){_year year;_month month;_day day;}private:int _year;int _month;int _…

Neepu2023-部分Reserve复现

目录 Base IKUN检查器 dnSpy junk code Cheat Engine工具使用&#xff1a; 奇怪的ELF mov混淆问题&#xff1a; Xor Base 打开附件&#xff0c;可以看到主函数 先是给出一个物理题&#xff0c;要求输入答案&#xff0c;这个无关紧要&#xff0c;接着要求输入一串字符&…