当前位置: 首页 > news >正文

五种IO模型

用户空间与内核空间

操作系统把内存空间划分成了两个部分:内核空间和用户空间。
为了保护内核空间的安全,操作系统一般都限制用户进程直接操作内核。

所以,当我们使用TCP发送数据的时候,需要先将数据从用户空间拷贝到内核空间,再由内核空间拷贝到网卡;
当我们使用TCP读取数据的时候,数据需要先从网卡拷贝到内核空间,再从内核空间拷贝到用户空间供用户进程使用。

在这里插入图片描述

内核空间与网卡的数据拷贝使用DMA技术,不需要CPU参与。

缓存IO

缓存I/O又被称作标准I/O,大多数文件系统的默认I/O操作都是缓存I/O。 在Linux的缓存I/O机制中,
数据先从磁盘复制到内核空间的缓冲区(PageCache), 然后从内核空间缓冲区复制到应用程序的地址空间。

读操作 操作系统检查内核的缓冲区有没有需要的数据,如果已经缓存了,那么就直接从缓存中返回;
否则从磁盘中读取,然后缓存在操作系统的缓存中。

写操作 将数据从用户空间复制到内核空间的缓存区。这时对用户程序来说写操作就已经完成,
至于什么时候再写到磁盘中由操作系统决定,除非显示地调用了sync同步命令。

缓存I/O的优点 首先,在一定程度上分离了内核空间和用户空间,保护系统本身的运行安全;
其次,可以减少读盘的次数,从而提高性能。

缓存I/O的缺点 在缓存 I/O 机制中,DMA方式可以将数据直接从磁盘读到页缓存中,
或者将数据从页缓存直接写回到磁盘上,而不能直接在应用程序地址空间和磁盘之间进行数据传输,
这样,数据在传输过程中需要在应用程序地址空间(用户空间)和缓存(内核空间)之间进行多次数据拷贝操作,
这些数据拷贝操作所带来的CPU以及内存开销是非常大的。

IO模式

对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,
然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间(用户空间)。

所以说,当一个read操作发生时,它会经历两个阶段:

1.内核空间准备好数据

2.将数据从内核空间拷贝到用户空间

因为这两个阶段,Linux系统产生了下面五种IO模型

阻塞型IO

当用户进程发起read操作,一直阻塞直到数据拷贝到用户空间为止才返回。

阻塞型IO第一阶段和第二阶段都阻塞。

在这里插入图片描述

非阻塞型IO

非阻塞型IO,用户进程不断询问内核,数据准备好了吗?
一直重试,直到内核说数据准备好了,然后把数据从内核空间拷贝到用户空间,返回成功,开始处理数据。

非阻塞型IO第一阶段不阻塞,第二阶段阻塞。

在这里插入图片描述

IO多路复用

IO多路复用,会将多个Socket注册到一个选择器(Selector)。
相当于可以使用一个线程来管理多个Socket连接。在最初的阻塞型IO,每来一个新的连接都需要分配一个线程来处理。

IO多路复用有三种模式:select、poll、epoll。当用户调用select/poll/epoll,会阻塞当前进程,
内核会不断的轮询注册到选择器(Selector)上的Socket,当任何一个Socket的数据准备好了,就会结束阻塞。
这个时候用户进程再调用read操作,将数据从内核空间拷贝到用户空间。

IO多路复用,第一阶段会阻塞在Selector上,第二阶段拷贝数据也会阻塞。

在这里插入图片描述

信号驱动IO

信号驱动IO,用户进程发起read请求之前先注册一个信号给内核说明自己需要什么数据,这个注册请求立即返回。
等内核数据准备好了,主动通知用户进程,用户进程再去请求读取数据,此时,需要等待数据从内核空间拷贝到用户空间再返回。

信号驱动,第一阶段不阻塞,第二阶段阻塞。

在这里插入图片描述

异步IO

异步IO,用户进程发起read请求后立马返回,当数据完全拷贝到用户空间后通知用户直接使用数据。

异步IO,两个阶段都不阻塞。

在这里插入图片描述

阻塞与非阻塞

阻塞:是指调用结果返回之前,当前线程会被挂起,直到调用结果返回。

比如Socket编程中,使用java.io.InputStream#read(byte[])方法读取数据,
如果没有可读数据,就会一直阻塞当前线程,直到有可读数据才会返回。

非阻塞:不能立即得到结果之前,当前线程不被挂起,而是可以继续做其它的事。

同步与异步

同步:调用者会被阻塞直到IO操作完成,调用的结果随着请求的结束而返回。。

异步:调用者不会被阻塞,调用的结果不随着请求的结束而返回,而是通过通知或回调函数的形式返回。

阻塞/非阻塞,更关心的是当前线程是不是被挂起。

同步/异步,更关心的是调用结果是不是随着请求结束而返回。

阻塞是指整个IO过程中是否有阻塞,所以,
阻塞型IO、非阻塞型、IO多路复用、信号驱动IO都是同步IO,只有最后一种才是异步IO。

http://www.lryc.cn/news/40475.html

相关文章:

  • 5 全面认识java的控制流程
  • 第二章 测验【嵌入式系统】
  • 排序算法之插入排序
  • Kaggle实战入门:泰坦尼克号生生还预测
  • 【大汇总】11个Python开发经典错误(1)
  • Java中的异常
  • L2-022 重排链表 L2-002 链表去重
  • 【手撕八大排序】——插入排序
  • flink多流操作(connect cogroup union broadcast)
  • 漫画:什么是快速排序算法?
  • vue 3.0组件(下)
  • 双指针 -876. 链表的中间结点-leetcode
  • Linux之运行级别
  • python搭建web服务器
  • 【SpringCloud】SpringCloud Feign详解
  • 更改Hive元数据发生的生产事故
  • 《Netty》从零开始学netty源码(八)之NioEventLoop.selector
  • TCP UDP详解
  • 超详细淘宝小程序的接入开发步骤
  • 【Python】正则表达式re库
  • JDK8使用Visual VM根据Dump文件排查OutOfMemoryError生产问题思路
  • 2023年网络安全比赛--网络安全事件响应中职组(超详细)
  • 【半监督学习】3、PseCo | FPN 错位对齐的高效半监督目标检测器
  • Tomcat+Servlet初识
  • ChatGPT-4 终于来了(文末附免费体验地址)
  • 【C++学习】类和对象(中)一招带你彻底了解六大默认成员函数
  • 面试——Java基础
  • JavaWeb——Request(请求)和Response(响应)介绍
  • JMeter压测文件上传接口和中文乱码
  • CSRF漏洞复现