Linux 5种IO模型

news2024/12/26 21:43:43

Linux IO模型

网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。刚才说了,对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段:

  1. 第一阶段:等待数据准备 (Waiting for the data to be ready)。

  2. 第二阶段:将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)。

对于socket流而言,

  1. 第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。

  2. 第二步:把数据从内核缓冲区复制到应用进程缓冲区。

1、阻塞IO模型 

在 linux 中,默认情况下所有的 socket 都是阻塞的。

对于socket流而言,

  1. 第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。

  2. 第二步:把数据从内核缓冲区复制到应用进程缓冲区。

当用户进程调用了 read 这个系统调用, kernel 就开始了 IO 的第一个阶段:准备数据。对于network io 来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的数据包),这个时候 kernel 就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当 kernel一直等到数据准备好了,它就会将数据从 kernel 中拷贝到用户内存,然后 kernel 返回结果,用户进程才解除 block 的状态,重新运行起来。

所谓阻塞型接口是指系统调用(一般是 IO 接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。实际上,除非特别指定,几乎所有的 IO 接口 ( 包括 socket 接口 ) 都是阻塞型的。这这就带来了一个很大的问题,如在调用 send()的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求,一个简单的改进方案是在服务器端使用多线程(或多进程)

2、非阻塞IO模型 

Linux 下,可以通过设置 socket 使其变为 non-blocking。当对一个 non-blocking socket 执行读操作时,流程是这个样子:

 

同步非阻塞就是 “每隔一会儿瞄一眼进度条” 的轮询(polling)方式。在这种模型中,设备是以非阻塞的形式打开的。这意味着 IO 操作不会立即完成,read 操作可能会返回一个错误代码,说明这个命令不能立即满足(EAGAIN 或 EWOULDBLOCK)。

在网络IO时候,非阻塞IO也会进行recvform系统调用,检查数据是否准备好,与阻塞IO不一样,"非阻塞将大的整片时间的阻塞分成N多的小的阻塞, 所以进程不断地有机会 '被' CPU光顾"。

也就是说非阻塞的recvform系统调用调用之后,进程并没有被阻塞,内核马上返回给进程,如果数据还没准备好,此时会返回一个error。进程在返回之后,可以干点别的事情,然后再发起recvform系统调用。重复上面的过程,循环往复的进行recvform系统调用。这个过程通常被称之为轮询。轮询检查内核数据,直到数据准备好,再拷贝数据到进程,进行数据处理。需要注意,拷贝数据整个过程,进程仍然是属于阻塞的状态

3、多路复用IO模型 

解决服务器对多个连接套接字的读取的关键:

1、是需将可读判断与实际读取数据相分离。

2、是能同时支持多个套接字可读判断。

因此我们需要一种能够预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪,即输入已经准备好被读取,它就通知进程。这个行为称之为I/O复用。在Linux平台上,提供了select、poll和epoll这几种系统调用作为I/O复用的方式。

select/epoll的好处就在于单个线程就可以同时处理多个网络连接的IO。它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

其中的任意一个描述符进入读就绪状态,select, poll,epoll函数就可以返回。对于监视的方式,又可以分为 select, poll, epoll三种方式。

如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。(select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)

IO多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。

在I/O编程过程中,当需要同时处理多个客户端接入请求时,可以利用多线程或者I/O多路复用技术进行处理。I/O多路复用技术通过把多个I/O的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。

select、poll、epoll 区别总结:

1、支持一个进程所能打开的最大连接数

select:单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。

poll:poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的。

epoll:虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接。

2、fd剧增后带来的IO效率问题

select:因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。

poll:同上

epoll:因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。

3、 消息传递方式

select:内核需要将消息传递到用户空间,都需要内核拷贝动作

poll:同上

epoll:epoll通过内核和用户空间共享一块内存来实现的。
 

优点:

与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降底了系统的维护工作量,节省了系统资源,I/O多路复用的主要应用场景如下:

1、服务器需要同时处理多个处于监听状态或者多个连接状态的套接字。

2、服务器需要同时处理多种网络协议的套接字。

同步模型:

了解了前面三种IO模式,在用户进程进行系统调用的时候,他们在等待数据到来的时候,处理的方式不一样,直接等待,轮询,select或poll轮询。从整个IO过程来看,他们都是顺序执行的,因此可以归为同步模型(synchronous)。都是进程主动等待且向内核检查状态。

高并发的程序一般使用同步非阻塞方式而非多线程 + 同步阻塞方式。要理解这一点,首先要扯到并发和并行的区别。比如去某部门办事需要依次去几个窗口,办事大厅里的人数就是并发数,而窗口个数就是并行数。也就是说并发数是指同时进行的任务数(如同时服务的 HTTP 请求),而并行数是可以同时工作的物理资源数量(如 CPU 核数)。通过合理调度任务的不同阶段,并发数可以远远大于并行度,这就是区区几个 CPU 可以支持上万个用户并发请求的奥秘。

注意:关于IO多路复用是同步阻塞模型还是异步阻塞模型?在此给大家分析下:

同步是需要主动等待消息通知,而 异步则是被动接收消息通知,通过回调、通知、状态等方式来被动获取消息。IO多路复用在阻塞到select阶段时,用户进程是主动等待并调用select函数获取数据就绪状态消息,并且其进程状态为阻塞。所以,把IO多路复用归为同步阻塞模式。

4、信号驱动IO模型 

首先我们允许Socket进行信号驱动IO,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。

5、异步IO模型 

相对于同步IO,异步IO不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知IO两个阶段,进程都是非阻塞的

Linux提供了AIO库函数实现异步,但是用的很少。目前有很多开源的异步IO库,例如libevent、libev、libuv。异步过程如下图所示:

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

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

相关文章

【测试开发】基于 MeterSphere 的接口测试流程

基于 MeterSphere 的接口测试流程 MeterSphere 接口测试模块提供了 接口定义、接口自动化 等接口测试相关功能。 用户可以使用树状多级模块来分级分组管理项目下的接口列表,创建执行接口用例测试接口,组合编排多个接口用例进行场景自动化测试。 1 接口定…

caffe专题五——回归中——检测框架

一:Bounding-box regression回归 1.问题理解(为什么要做 Bounding-box regression? )如图 1 所示, 绿色的框为飞机的 Ground Truth, 红色的框是 Selective Search 提取的 Region Proposal。 那么即便红色的框被分类器识别为飞机,但…

Win10系统pytorch安装教程

前提:安装后Anaconda和NVIDIA显卡驱动 1. 确定支持的最高CUDA版本 确定支持的最高CUDA版本 记住这个CUDA版本,后面要用。 2. 新建conda虚拟环境 2.1 为conda配置清华镜像源 conda常用命令 打开Anaconda prompt窗口,使用如下命令&#xf…

学习心得01:STM32开发板

嵌入式开发也不难,相关知识需要学习。对于某个具体内容,需要反复测试、修改。 这是我买的一个开发板,各个范例都跑了一遍,有问题的还问过客服(更新代码后解决)。

[C++]笔记-函数的栈空间(避免栈空间溢出)

错误1 当数组的内存占用较大时,会引发异常 #include <iostream> using namespace std; int main() {char buff[2000000];cout << (int)buff[sizeof(buff) - 1] << endl; 错误 2 当调用次数较小的时候,栈内存还没有满,可以输出,该地址相减除以1024等于100,就…

​《乡村振兴战略下传统村落文化旅游设计 》在2023年畅销榜排名465位

​《乡村振兴战略下传统村落文化旅游设计 》在2023年畅销榜排名465位

T01西门子#将博图触摸屏中使用的外部图片全部导出

方法一&#xff1a;直接在博图软件WINCC中 点击图片右击 缺点&#xff1a;用自带的画图软件打开保存后无法保留透明。 方法二&#xff1a;使用官方软件导出 优点&#xff1a;快速批量全部导出&#xff0c;保留文件原格式。 下载地址&#xff1a; 将图形从 WinCC (TIA Portal) …

理解变分自编码器(VAE)

转载翻译自&#xff1a;https://towardsdatascience.com/understanding-variational-autoencoders-vaes-f70510919f73 介绍 在过去几年中&#xff0c;基于深度学习的生成模型因为在该领域中取得了一些惊人的进展而越来越受到关注。依靠大量的数据、精心设计的网络架构和智能训…

日志系统——实用类设计,日志等级类设计,日志消息类设计

一&#xff0c;实用类设计 该类主要是提前完成一些后面会用到的零碎通用的功能接口&#xff0c;主要有下面几个 1.获取系统时间&#xff1a;这里我们直接用time()函数获取时间返回 2.判断文件是否存在&#xff1a;判断文件我们调用系统接口&#xff0c;stat()&#xff0c;如下所…

Linux命令200例:top是一个基于终端的实时系统监控工具(常用)

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

新款2023奥迪A5新车32.24,这款车怎么样?

奥迪公司近期发布了新款A5车型&#xff0c;全国起售价为32.24万元。这款新车凭借其精致的设计和出色的实用性&#xff0c;吸引了大量消费者的关注。本文将结合个人经验和市场调研&#xff0c;对这款新车的特性进行深入剖析。 首先&#xff0c;奥迪A5的外观设计完美融合了实用性…

16.5 【Linux】SELinux 初探

16.5.1 什么是 SELinux SELinux是“ Security Enhanced Linux ”的缩写&#xff0c;字面上的意义就是安全强化的 Linux。 当初设计的目标&#xff1a;避免资源的误用 SELinux 是由美国国家安全局 &#xff08;NSA&#xff09; 开发的&#xff0c;当初开发这玩意儿的目的是因…

Centos7完全卸载已安装的Nginx

查看服务器上安装的nginx版本号&#xff0c;主要是通过ngix的-v或-V选项 Linux下查看Nginx安装目录、版本号信息? -v 显示 nginx 的版本。 -V 显示 nginx 的版本&#xff0c;编译器版本和配置参数。 [rootwww ~]# /usr/local/nginx/sbin/nginx -v nginx version: nginx/1.…

移动硬盘已识别但无法读取怎么办?

移动硬盘已识别但无法读取问题是一个比较常见的问题&#xff0c;通常会以“硬盘无法访问”的提示弹窗形式出现&#xff0c;也曾让很多人苦闷烦恼不已。那么具体的移动硬盘无法读取原因是什么呢&#xff1f; 移动硬盘无法读取的原因 硬盘驱动器可能是没有分区的新驱动器。如果您…

记一次:线程池源码解析

前言&#xff1a;很多时候我们需要使用线程池来处理逻辑&#xff0c;但实际上线程池是如何添加线程&#xff0c;如何执行的呢&#xff1f; 0&#xff1a;创建线程池--略&#xff08;7个参数&#xff09; 1&#xff1a;提交线程池源码 public void execute(Runnable command)…

基于 spring boot 的毕业生信息招聘管理系统【源码在文末】

向上的路&#xff0c;并不拥挤&#xff0c;拥挤是因为大部分人选择了安逸 大学生嘛&#xff0c;论文写不出&#xff0c;代码搞不懂不要紧&#xff0c;重要的是&#xff0c;从这一刻就开始学习&#xff0c;立刻马上&#xff01; 今天带来的是最新的选题&#xff0c;基于 spring…

Python绘图系统5:自定义一个坐标设置控件

文章目录 封装成类数据输入方案设置数据源代码 Python绘图系统&#xff1a;将matplotlib嵌入到tkinter &#x1f4c8;简单的绘图系统 &#x1f4c8;数据导入&#x1f4c8;三维绘图系统 封装成类 xyz这三行其实从代码的角度来说是完全一样的&#xff0c;而且在写这三行组件的时…

Python学习笔记_基础篇(九)_面向对象编程

本篇内容: 1、反射2、面向对象编程3、面向对象三大特性4、类成员5、类成员修饰符6、类的特殊成员7、单例模式 反射 python中的反射功能是由以下四个内置函数提供&#xff1a;hasattr、getattr、setattr、delattr&#xff0c;改四个函数分别用于对对象内部执行&#xff1a;检…

VS2012+AO 10.2.2 项目错误 之内部编译器错误: 步骤“EMIT”

调试时异常消息&#xff1a; 内部编译器错误: 步骤“EMIT” 内部编译器错误: 步骤“COMPILE”的符号 内部编译器错误: 步骤“COMPILE”的符号“<全局命名空间>” 内部编译器错误(0xc0000005 位于地址 00C9FDDC 处): 可能的原因是“CODEGEN”。 好好的项目&…

【逐步剖C++】-第一章-C++入门知识

前言&#xff1a;本文主要介绍有关C入门需掌握的基础知识&#xff0c;包括但不限于以下几个方面&#xff0c;这里是文章导图&#xff1a; 本文较长&#xff0c;内容较多&#xff0c;大家可以根据需求跳转到自己感兴趣的部分&#xff0c;希望能对读者有一些帮助 那么本文也主要以…