【JavaSE】IO模型

        IO,英文全称是 Input/Output,翻译过来就是输入/输出。我们听得挺多,就是磁盘 IO,网络 IO 等。IO 即输入/输出,到底谁是输入?谁是输出?IO 如果脱离了主体,会让人疑惑。

计算机角度的 IO

        我们常说的输入输出,比较直观的意思就是计算机的输入输出,计算机就是主体。计算机分成分为 5 个部分:运算器、控制器、存储器、输入设备、输出设备。输入设备是向计算机输入数据和信息的设备,键盘,鼠标都属于输入设备;输出设备是计算机硬件系统的终端设备,用于接收计算机数据的输出显示,一般显示器、打印机属于输出设备。

操作系统角度的 IO

        我们要将内存中的数据写入到磁盘的话,那么主体就是一个程序。操作系统负责计算机的资源管理和进程的调度,我们电脑上跑着的应用程序,其实是需要经过操作系统,才能做一些特殊操作,如磁盘文件读写内存的读写等等。

        真正的 IO 是在操作系统执行的。即应用程序的 IO 操作分为两种动作:IO 调用IO 执行。IO 调用是由进程(应用程序的运行态)发起,而 IO 执行是操作系统内核的工作。

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

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

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

IO 模型

阻塞 IO

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

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

非阻塞 IO

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

        非阻塞 IO 的流程如下:

        1.应用进程向操作系统内核,发起 recvfrom( )读取数据。

        2.操作系统内核数据没有准备好,立即返回 EWOULDBLOCK 错误码。

        3. 应用程序进程轮询调用,继续向操作系统内核发起 recvfrom 读取数据。

        4.操作系统内核数据准备好了,从内核缓冲区拷贝到用户空间。

        5.完成调用,返回成功提示。

        recvfrom() 用来接收远程主机经指定的 socket 传来的数据,并把数据传到由参数 buf 指向的内存空间。非阻塞 IO 模型,简称 NIO,Non-Blocking IO。它相对于阻塞 IO,虽然大幅提升了性能,但是它依然存在性能问题,即频繁的轮询,导致频繁的系统调用,同样会消耗大量的 CPU 资源。

IO 多路复用

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

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

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

select

        应用进程通过调用 select 函数,可以同时监控多个 fd,在 select 函数监控的 fd中,只要有任何一个数据状态准备就绪了,select 函数就会返回可读状态,这时应用进程再发起 recvfrom( )请求去读取数据。select 的 IO 多路复用模型,只需要发起一次询问就够了,大大优化了性能。

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

epoll

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

select、poll、epoll 的区别

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

异步 IO

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

        异步 IO 的优化思路很简单,只需要向内核发送一次请求,就可以完成数据状态询问和数据拷贝的所有操作,并且不用阻塞等待结果。日常开发中,有类似思想的业务场景:比如发起一笔批量转账,但是批量转账理比较耗时,这时候后端可以先告知前端转账提交成功,等到结果处理完,再通知前端结果即可。

一个生活中经典例子:

BIO

小明去吃饭,就这样在那里排队,等了一小时,轮到她了,然后才开始吃饭。

package IO;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class BIODemo1 {public static void main(String[] args) throws IOException, InterruptedException {ServerSocket serverSocket = new ServerSocket(9999, 1024);System.out.println("服务器启动");while (true) {Socket socket = serverSocket.accept();}}}
package IO;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class BIODemo2 {public static void main(String[] args) throws IOException, InterruptedException {//创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(50,50, 200,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());ServerSocket serverSocket = new ServerSocket(9999, 1024);System.out.println("服务器启动");while (true) {Socket socket = serverSocket.accept();System.out.println(socket + "连接到服务器");executor.execute(() -> {//执行任务});}}}
package IO;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;/*** BIO模拟NIO*/
public class BIODemo3 {public static void main(String[] args) throws IOException, InterruptedException {List<Socket> list = new ArrayList<>();ServerSocket serverSocket = new ServerSocket(9999, 1024);System.out.println("服务器启动");while (true) {// 设置非阻塞 serverSocket.set不阻塞Socket socket = serverSocket.accept(); // 不管接到接不到继续向下执行// 判断有没有接到if (socket != null) { // 没有人连接到服务器// 虽然没有人连接,但是有可能有人发送消息,此时也需要处理.// 循环集合中的socket} else { // 有人连接到服务器System.out.println(socket + "连接到服务器");list.add(socket);// 循环集合中的socket}}}}

NIO

        小红也去吃饭,她一看要等挺久的,于是去逛会商场,每次逛一下,就跑回来看看,是不是轮到她了。于是最后她既购了物,又吃上饭了。

package IO;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class NIODemo1 {public static void main(String[] args) throws IOException {FileInputStream in = new FileInputStream("E:/source.txt");FileOutputStream out = new FileOutputStream("E:/dest.txt");FileChannel inchannel = in.getChannel();FileChannel outchannel = out.getChannel();ByteBuffer byteBuffer = ByteBuffer.allocate(1024);while (inchannel.read(byteBuffer) != -1) {byteBuffer.flip();outchannel.write(byteBuffer);byteBuffer.clear();}}}
package IO;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;/*NIO完整写法*/
public class NIODemo2 {public static void main(String[] args) throws InterruptedException, IOException {List<SocketChannel> list = new ArrayList<>();ServerSocketChannel serverSogketChannel = ServerSocketChannel.open();//创建服务器serverSogketChannel.bind(new InetSocketAddress(9999), 1024);serverSogketChannel.configureBlocking(false);//设置非阻塞//注册选择器Selector selector = Selector.open();//创建选择器serverSogketChannel.register(selector, SelectionKey.OP_ACCEPT);//向selector注册管道System.out.println("启动服务器");for (; ; ) {selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();//返回所有选择器接收到的操作Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();if (selectionKey.isAcceptable()) {//连接ServerSocketChannel serverSockChannel = (ServerSocketChannel) selectionKey.channel();SocketChannel acceptSocketChannel = serverSockChannel.accept();System.out.println(acceptSocketChannel.getRemoteAddress());acceptSocketChannel.configureBlocking(false);acceptSocketChannel.register(selector, SelectionKey.OP_WRITE);}if (selectionKey.isWritable()) {//写SocketChannel socketChannel = (SocketChannel) selectionKey.channel();String resp = "响应";try {Thread.sleep(500);socketChannel.write(ByteBuffer.wrap(resp.getBytes()));} catch (Exception e) {e.printStackTrace();}}if (selectionKey.isReadable()) {//读SocketChannel channel = (SocketChannel) selectionKey.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int length = channel.read(buffer);String msg = "server receive msg:" + new String(buffer.array(), 0, length);System.out.println(msg);}iterator.remove();}}}
}

AIO

        小华一样,去吃饭,由于他是高级会员,所以店长说,你去商场随便逛会吧,等下有位置,我立马打电话给你。于是小华不用干巴巴坐着等,也不用每过一会儿就跑回来看有没有等到,最后也吃上了饭。

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

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

相关文章

快递物流查询-快递查询-快递单号查询-快递物流单号查询-快递物流轨迹查询-快递物流查询接口

快递物流查询接口&#xff08;API&#xff09;是一种允许开发者通过编程方式实时查询快递物流信息的服务。这些接口通常集成了多家快递公司的物流数据&#xff0c;为电商平台、物流管理系统、个人用户等提供便捷的物流查询服务。以下是关于快递物流查询接口的一些详细介绍&…

哪有什么三教九流,物以类聚罢了——kmeans聚类算法

观察人类社会&#xff0c;亦或说车水马龙中的光怪陆离&#xff0c;不难发现《马原》中介绍的人类社会中的个体&#xff0c;总是通过某种方面的“类似”聚在一起&#xff0c;文学上称这种现象叫做物以类聚&#xff0c;人以群分。 一.引言 前文提到&#xff0c;每个数据项&#x…

SpringBoot项目License证书生成与验证(TrueLicense) 【记录】

SpringBoot项目License证书生成与验证(TrueLicense) 【记录】 在非开源产品、商业软件、收费软件等系统的使用上&#xff0c;需要考虑系统的使用版权问题&#xff0c;不能随便一个人拿去在任何环境都能用。应用部署一般分为两种情况&#xff1a; 应用部署在开发者自己的云服务…

Qt笔记(十七)cmake编译Qt项目

Qt笔记&#xff08;十七&#xff09;cmake编译Qt项目 1. 文件内容与文件结构1.1.文件目录1.2. CMakeLists.txt内容1.3. main.cpp文件1.4. mouseevent.h1.5. mouseevent.cpp1.6. 生成Visual Studio项目后编译报错1.7. 界面显示中文乱码问题 1. 文件内容与文件结构 1.1.文件目录…

jdk11特性介绍

JDK 11&#xff08;也称为Java 11&#xff09;是Java平台的一个重要版本&#xff0c;它引入了许多新特性和改进&#xff0c;旨在提高开发者的生产力和Java平台的性能。以下是一些JDK 11的主要特性&#xff1a; 局部变量类型推断&#xff08;Local-Variable Syntax for Lambda P…

2009考研数学真题解析-数二:

第一题&#xff1a; 解析&#xff1a;先找间断点&#xff1a;分母不能等于0&#xff0c;分母是sinΠx&#xff0c; 因此不难看出间断点是x0&#xff0c;-1&#xff0c;-2&#xff0c;-3。。。。。 接着一个一个来算这些点是什么间断点。 &#xff0c;从x趋于2开始&#xff0c;分…

JavaScript是如何来的~~

文章目录 前言一、网络的诞生 ( The birth of the Web )二、Mosaic 浏览器三、Netscape 浏览器四、JavaScript的诞生 ~ 千呼万唤始出来总结 前言 例如&#xff1a;想要了解一门语言的发展历程&#xff0c;首先你得知道它是怎么来的&#xff0c;所以本文开篇介绍了网络的基本发…

智能BI平台项目

1.项目介绍 BI商业智能&#xff1a;数据可视化、报表可视化系统 4&#xff09;发布订阅 Resource 是基于名称进行查找的&#xff0c;而Spring框架中更常用的 Autowired 则是基于类型进行查找的。如果找不到匹配的bean&#xff0c;Autowired 会抛出异常&#xff0c;而 Resource…

EAGLE——探索混合编码器的多模态大型语言模型的设计空间

概述 准确解释复杂视觉信息的能力是多模态大型语言模型 (MLLM) 的关键重点。最近的研究表明&#xff0c;增强的视觉感知可显著减少幻觉并提高分辨率敏感任务&#xff08;例如光学字符识别和文档分析&#xff09;的性能。最近的几种 MLLM 通过利用视觉编码器的混合来实现这一点…

网络层协议 —— IP协议

目录 0.前言 1.IP协议的格式 2.IP地址 2.1IP地址的划分 国际间IP地址的划分 公有IP 私有IP 特殊的IP地址 国内IP地址的划分 2.2IP地址不足问题 2.3IP地址的功能 2.4如何使用IP地址 2.5IP地址的构成 3.网段划分 以前的方案 现在的方案 4.认识宏观网络 5.路由 …

SpringCloud config native 配置

SpringCloud config native 配置 1.概述 最近项目使用springCloud 框架&#xff0c;使用config搭建git作为配置中心。 在私有化部署中&#xff0c;出现很多比较麻烦的和鸡肋的设计。 每次部署都需要安装gitlab 有些环境安装完gitlab&#xff0c;外面不能访问&#xff0c;不给开…

QT实现升级进度条页面

一.功能说明 在Qt中实现固件升级的进度条显示窗口&#xff0c;你可以通过创建一个自定义的对话框&#xff08;Dialog&#xff09;来完成。这个对话框可以包含一个进度条&#xff08;QProgressBar&#xff09;、一些文本标签&#xff08;QLabel&#xff09;用于显示状态信息&am…

SSL 最长签发时间是多久?

在当今数字化的时代&#xff0c;网络安全变得至关重要。为了确保数据在网络传输中的安全性&#xff0c;SSL&#xff08;Secure Sockets Layer&#xff0c;安全套接层&#xff09;证书被广泛应用。那么&#xff0c;SSL最长签发时间是多久呢&#xff1f; SSL证书是一种数字证书&…

差分数组介绍

差分数组 差分数组介绍定义性质性质1: 计算数列第i项的值性质2: 计算数列第i项的前缀和应用场景差分数组具体示例【leetcode】370.区间加法题目描述题解【leetcode】1109. 航班预订统计题目描述题解【leetcode】2848.与车相交的点题目描述题解差分数组介绍 定义 对于已知有n个…

C#如何把写好的类编译成dll文件

1 新建一个类库项目 2 直接改写这个Class1.cs文件 3 记得要添加Windows.Forms引用 4 我直接把在别的项目中做好的cs文件搞到这里来&#xff0c;连文件名也改了&#xff08;FilesDirectory.cs&#xff09;&#xff0c;这里using System.Windows.Forms不会报错&#xff0c;因为前…

制造解法 Manufactured Solutions 相关的论文的阅读笔记

Verification of Euler/Navier–Stokes codes using the method of manufactured solutions https://doi.org/10.1002/fld.660 粘性项与扩散项之间的平衡 For the Navier–Stokes simulations presented herein, the absolute viscosity is chosen to be a large constant va…

【Java】掌握Java:基础概念与核心技能

文章目录 前言&#xff1a;1. 注释2. 字面量3. 变量详解3.1 变量的定义3.2 变量里的数据存储原理3.3 数据类型3.4 关键字、标识符 4. 方法4.1 方法是啥&#xff1f;4.2 方法的完整定义格式4.3 方法如何使用&#xff1a;4.4 方法的其他形式4.5 方法的其他注意事项4.5.1 方法是可…

如何充分使用芝士AI呢?一文讲清楚助力论文完成无忧

为了解决各位学弟学妹们的论文烦恼&#xff0c;助力大家毕业无忧&#xff0c;芝士AI由985硕博团队的学长学姐们潜心研发出来的一款集齐论文选题、开题报告、论文初稿、论文查重、论文降重、论文降AIGC率、论文答辩稿、论文答辩PPT&#xff0c;一站式解决困扰大家已久的论文问题…

如何创建标准操作规程(SOP)[+模板]

创建、分发和管理流程文档和逐步说明的能力是确定企业成功的关键因素。许多组织依赖标准操作规程&#xff08;SOP&#xff09;作为基本形式的文档&#xff0c;指导他们的工作流程操作。 然而&#xff0c;SOP不仅仅是操作路线图&#xff1b;它们就像高性能车辆中的先进GPS系统一…

机器视觉-7 检测原理之预处理(图像增强)

在图像处理领域&#xff0c;图像增强是一个非常重要的技术&#xff0c;目的是通过调整图像的某些特征来改善图像的视觉效果&#xff0c;或为后续的图像分析和处理做准备。在 OpenCV 中&#xff0c;C 提供了多种图像增强方法&#xff0c;包括直方图均衡化、对比度拉伸、锐化、边…