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

这篇具有很好参考价值的文章主要介绍了Java基础--->IO流(2)【常见IO模型】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

计算机角度IO

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

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

从计算机结构的视角来看的话, 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】

Java基础--->IO流(2)【常见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】

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

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

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

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

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

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

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

IO多路复用

Java基础--->IO流(2)【常见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】

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

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

大概总结一下是这样

Java基础--->IO流(2)【常见IO模型】文章来源地址https://www.toymoban.com/news/detail-461754.html

到了这里,关于Java基础--->IO流(2)【常见IO模型】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包