操作系统的中的 IO
文章目录
- IO 是什么
- I/O模型
- 阻塞 IO
- 非阻塞 IO
- IO 多路复用
- 信号驱动式 IO
- 异步 IO
- 五种 IO 模型对比
IO 是什么
IO 全称为 Input/Output ,翻译过来就是 输入/输出。
计算机角度的 IO
我们日常所说的输入输出,比较直观的意思就是计算机的输入/输出,计算机就是主体。
在计算机当中我们可以分为 5 个部分:运算器、控制器、存储器、输入十本、输出设备。
输入设备是向计算机输入数据和信息的设备,键盘,鼠标都是属于输入设备;
输出设备是向计算机硬件系统的终端设备,用于接收计算机数据的输出显示。像显示器、打印机就都是属于输出设备。
操作系统角度的 IO
我们要将内存中的数据写入到磁盘的话,那么主体就是一个程序。
操作系统就是负责计算机的资源管理和进程的调度,我们电脑运行着的应用程序,其实是需要经过操作系统,才能做出一些特殊的操作,如磁盘文件的读写,内存的读写等等。
真正的 IO 是在操作系统上执行的。即当前程序的 IO 操作分为两种动作:IO 调用和 IO 执行。IO 调用是由进程(应用程序的运行态)发起的,而 IO 执行是操作系统内核的工作。
而应用程序发起的一次 IO 操作是包含了两个阶段的:
IO 调用:应用程序进程向操作系统内核发起调用。
IO 执行:操作系统内核完成 IO 操作。
I/O模型
阻塞 IO
假设应用程序的进程发起 IO 调用,但是如果内核的数据还没有准备好的话,那么应用程序进程就一直在阻塞等待,一直等到内核数据准备好了,从内核拷贝到用户空间,才返回成功提示,此次 IO 操作,就称呼为 阻塞 I/O;
阻塞 I/O 比较经典的应用就是 阻塞 socket,Java BIO。
优点:开发简单,容易入门;在阻塞等待期间,用户线程挂起,在挂起期间是不会占用 CPU 资源的。
缺点:一个线程维护一个 IO,是不适合大并发,在并发量大的时候需要创建大量的线程来维护网络的连接,内存、线程开销也非常大。
非阻塞 IO
就是在内核还没有准备好数据的时候就会返回错误码,而调用的程序是不会休眠的,而是不断轮询询问内核数据是否准备好。
如果数据没有准备好的话,不像阻塞式 IO 那样会一直被阻塞,而是返回一个错误码,数据准备好的时候,函数就成功返回。
应用程序对这样一个非阻塞描述符循环调用称为轮询。
非阻塞式 IO 的轮询会耗费大量的 CPU ,通常在专门提供某一功能的系统中才会被使用,通过为套接字的描述符属性设置为非阻塞式,可使用该功能。
非阻塞 IO 的流程:
● 应用进程向操作系统内核,发起 recvfrom() 读取数据。
● 操作系统内核数据没有准备好,立即返回 EWOULDBLOCK 错误码。
● 应用程序进程轮询调用,继续向操作系统内核发起 recvfrom 速去数据。
● 操作西游内核数据准备好了,从内核缓冲区拷贝到用户空间。
● 完成调用,返回成功提示。
recvfrom() 用来接收远程主机指定的 socket 传来的数据,并把数据传到由参数 buf 指向的内存空间。
优点:每次发起 IO 调用,在内核等待数据的过程中可以立即返回,用户线程不会阻塞,实时性较好。
缺点:多个线程不断轮询内核是否有数据,占用大量 CPU 的时间,效率不高。一般 Web 服务器不会采用此模式。在针对这个问题,就可以使用 IO 复用模型去解决这个问题。
IO 多路复用
类似于非阻塞,只不过轮询不是由用户线程去执行的,而是由内核去轮询的,内核监听程序监听到数据准备好后,调用内核函数复制数据到用户态。
select 这个系统调用,充当代理类的角色,不断轮询注册到它这里的所有需要的 IO 文件描述符,有结果时,把结果告诉被代理的 recvfrom 函数,它本身再亲自出马去拿数据。
IO 多路复用至少有两次系统调用,如果只有一个代理对象,性能上是不如前面的 IO 模型的,但是由于它可以同时监听很多套接字,所以性能比前两个都好。
IO 多路复用的核心思想:系统给我们提供了一个函数(如:select、poll、epool),它们可以同时监听多个 fd 的操作,任何一个返回内核数据就绪,应用进程再发起 recvfrom 系统调用。
fd : 文件描述符(File Descriptor),它是计算机科学中的一个术语,形式上是一个非负整数,当程序打开一个现有文件或者创建一个新文件的时候,内核向进程返回一个文件的描述符。
在多路复用里包括:
● select:线性扫描所有监听的文件描述符,不管他们是不是活跃的,有最大数据的限制(32位系统里面为 1024,64位操作系统里面为 2048)
● poll:和 select 一样,不过数据结构不同,需要分配一个 pollfd 结构数组,维护在内核中,它没有大小限制,不过需要很多复制操作。
● epoll:用于代替 select 和 poll 。它没有大小限制,使用一个文件描述符(fd)管理多个文件描述符,使用红黑树存储,同时用事件驱动代替了轮询。epoll_ctl 中注册的文件描述符在时间触发的时候会通过回调机制激活该文件描述符。epoll_wait 便会收到通知,最后,epoll 还采用了 mmap 虚拟内存映射技术较少用户态和内核态数据传输的开销。
epoll 这里去掉了遍历文件描述符的坑爹操作,而是采用了监听事件回调的机制,这就是 epoll 最大的亮点。
优点:系统不必创建维护大量的线程,只使用一个线程,一个选择器即可同时处理成千上万个连接,大大较少了系统的开销。
缺点:在本质上,elect/poll系统调用的是阻塞式的,是属于同步 IO,需要在读写操作就绪后,由系统调用进行阻塞的读写。
select、poll、epoll区别
select | poll | epoll | |
---|---|---|---|
底层数据结构 | 数组 | 链表 | 红黑数和双链表 |
获取就绪的fd | 遍历 | 遍历 | 事件回调 |
事件复杂度 | O(n) | O(n) | O(1) |
最大连接数 | 1024 | 无限制 | 无限制 |
fd数据拷贝 | 每次调用 select ,需要将 fd 数据从用户空间拷贝到内核空间 | 每次调用 poll,需要将 fd 数据从用户空间拷贝到内核空间 | 使用内存映射(mmap),不需要从用户空间频繁拷贝 fd 数据到内核空间。 |
信号驱动式 IO
在上面 epoll 明显的优化了 IO 的执行效率,但在进程中调用 epoll_wait() 时,仍然可能会被阻塞。在这能不能不用我们老是去询问数据是否准备好,等发出请求后了,数据准备好了通知我就就行了,就诞生了 型号驱动 IO 模型
执行流程:
使用信号,内核在数据准备就绪的时候通过信号哎进行通知。
首先开启信号驱动 IO 套接字,并使用 sigaction 系统调用来安装信号处理程序,内核直接返回,不会阻塞用户态。
数据准备好时,内核会发送 SIGIO 信号,收到信号后开始进行 IO 操作。
说通俗一定就是:信号驱动下不会再主动询问的方式去确认数据是否就绪,而是向内核发送一个信号,然后应用用户进程就可以去做别的事,不用阻塞,当内核数据准备好后,载通过信号通知应用进程,数据准备好后的可读状态。应用用户进程收到信号之后,立即调用 recvfrom。去读区数据。
信号驱动 IO 模型,在应用进程发出信号后,是立即返回的,不会阻塞进程。它已经有一处操作的感觉了。但是上面的流程图当中。发现数据复制到应用缓冲的时候,应用进程还是阻塞的。回过头来看下这些IO在数据从内核复制到应用缓冲的时候,都是阻塞的。
异步 IO
异步 IO 依赖信号处理程序来进行通知。
不过异步 IO 与前面 IO 模型不同的是:前面的都是数据准备阶段的阻塞与非阻塞,异步 IO 模型通知的是 IO 操作已经完成,而不是数据准备完成。返回的不是处理结果,而是表示提示成功l类似的意思。
异步 IO 才是真正的非阻塞,主进程只负责做自己的事情,等 IO 操作完成(数据成功从内核缓存区复制到应用程序缓冲区)时通过回调函数对数据进行处理。
unix 中异步 IO 函数以 aio_或 lio_ 打头。
异步 IO 的优化思路是很简单的,只需要向内核发送一次请求,就可以完成数据状态的询问和数据拷贝的所有操作,并且不用阻塞等待结果。
优点:真正实现了异步非阻塞,吞吐量在这几种模式中是最高的。
缺点:应用程序主需要进行事件的注册与接收,其余工作都是交给了操作系统的内核,所以需要内核提供支持,在 Linux 系统中,异步 IO 在其2.6才引入,到目前为止也还不是非常完善,在底层的实现仍然使用的是epoll,与 IO 多路复用相同,因此在性能上是没有明显占优的。
五种 IO 模型对比
掐面 4 种 IO 模型的主要区别是在第一阶段,它们第二阶段是一样的;数据从内核缓冲去复制到调用者缓冲区期间都被阻塞住。
前面四种 IO 都是同步 IO;IO操作导致请求进程阻塞,直到 IO 操作完成。
异步 IO:IO 操作不导致请求进程阻塞。
IO 模型 | |
---|---|
阻塞 I/O 模型 | 同步阻塞 |
非阻塞 I/O 模型 | 同步非阻塞 |
I/O 多路复用模型 | 同步阻塞 |
信号驱动 I/O 模型 | 同步非阻塞 |
异步 I/O(AIO)模型 | 异步非阻塞 |
操作系统的中的 IO相关推荐
- Node的异步与java的异步_node中异步IO的理解
解释性语言和编译型语言的区别: 计算器不能直接的理解高级语言,只能理解机器语言,所以必须把高级语言翻译为机器语言,翻译的方式有两种,一个是编译,一个是解释. 解释性语言的程序不需要编译,它是在运行程序 ...
- mysql物理读和逻辑读,SQL Server中STATISTICS IO物理读和逻辑读的误区
SQL Server中STATISTICS IO物理读和逻辑读的误区 人人知道,SQL Server中可以行使下面下令查看某个语句读写IO的情形 SET STATISTICS IO ON 那么这个下令 ...
- node中异步IO的理解
解释性语言和编译型语言的区别: 计算器不能直接的理解高级语言,只能理解机器语言,所以必须把高级语言翻译为机器语言,翻译的方式有两种,一个是编译,一个是解释. 解释性语言的程序不需要编译,它是在运行程序 ...
- java io字符输出流_灵魂一击!详解Java中的IO输入输出流
什么是流?流表示任何有能力产生数据的数据源对象或者是有能力接收数据的接收端对象,它屏蔽了实际的I/O设备中处理数据的细节. IO流是实现输入输出的基础,它可以很方便地实现数据的输入输出操作,即读写操作 ...
- Java中五中IO模型详解
一.前言 在<Unix网络编程>一书中提到了五种IO模型,5种IO模型分别为: 阻塞IO模型.非阻塞IO模型.IO复用模型.信号驱动的IO模型.异步IO模型.下面就分别来介绍一下这5种IO ...
- [C++]C++中的IO类
C++中的IO类 C++语言不直接处理输入输出,而是通过一组定义在标准库中的类型来处理IO.这些类型支持从设备读取数据,向设备写入数据的IO操作,设备可以是文件,控制台窗口等.还有一些类型允许内存IO ...
- .net中的IO体系介绍
.net中对于IO流的支持分为两个层次:基于字节和基于字符两种方式. 基于字节的方式: 基于字节的方式适用于任何场合,因为任何文件的数据都是基于字节的方式有序存放的.基于字节的方式适用于操作二进制文件 ...
- java中的IO操作总结(一)
转载:http://www.cnblogs.com/nerxious/archive/2012/12/15/2818848.html 所谓IO,也就是Input与Output的缩写.在java中 ...
- java输出流输入流的使用_Java中的IO流之文件输入输出流
Java中的IO流之文件输入输出流 1.文件流介绍 文件流是以字节为单位进行读写文件的,所以属于字节流,并且是低级流.文件流位于java.io包下. 输入输出流分别是FileInputSteam和Fi ...
最新文章
- js模块化编程之CommonJS和AMD/CMD
- 矩阵论基础知识4——强大的矩阵奇异值分解(SVD)及其应用
- 用 JA Transmenu 模块做多级弹出菜单
- 前端学习(2579):组件库使用
- javascript 模块化机制
- Linux中$PATH详解
- 为什么excel图片会变成代码_会EXCEL便可定制自己的办公管理软件(超简单,无代码)...
- Vapnik-Chervonenkis Dimension 理解
- H3CIERS+(H3C认证路由交换互联网专家介绍)
- win7打开xp共享的计算机,xp/win7局域网共享软件
- 微型计算机原理与应用第三版王克义编著
- 如何防止form表单的重复提交
- eclipse找不到java虚拟机_eclipse无法启动 - 没有找到java虚拟机
- 【微信小编】动态地图gif制作
- 串口、终端应用程序 API termios
- 电脑点击计算机只能在任务栏显示桌面,windows7任务栏显示桌面按钮不见了怎么办?...
- EasyDemo*xxx企业xxx项目xxx功能测试用例模板
- 云呐|固定资产报废如何处理(固定资产报废如何处理残值)
- ACDSee清除旧版本残余
- 5个很棒的JavaScript Promise函数应用