Linux五种IO模型的使用解读

2025-09-24 00:50

本文主要是介绍Linux五种IO模型的使用解读,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Linux五种IO模型的使用解读》文章系统解析了Linux的五种IO模型(阻塞、非阻塞、IO复用、信号驱动、异步),重点区分同步与异步IO的本质差异,强调同步由用户发起,异步由内核触发,通过对比各模...

最近一直在研究linux IO模型,Linux IO模型是一个挺复杂的概念,分析Linux IO模型一定要注意方法,否则会在一个个概念中,迷失自我。

1.IO模型简介

Linux IO模型是指Linux操作系统中用于实现输入输出的一种机制。

Linux IO模型主要分为五种:

阻塞IO、非阻塞IO、IO复用、信号驱动IO和异步IO。

  • 阻塞IO是最常见的IO模型,当用户进程发起一个IO请求后,内核会一直等待,直到IO操作完成并返回结果。在此期间,用户进程会被阻塞,无法进行其他操作。
  • 非阻塞IO是在阻塞IO的基础上进行改进的一种IO模型。当用户进程发起一个IO请求后,内核会立即返回一个错误码,表示IO操作还未完成。用户进程可以继续进行其他操作,随后再通过轮询的方式来查询IO操作是否完成。
  • IO复用是指通过select、poll、epoll等系统调用来监听多个文件描述符的IO事件。当某个文件描述符就绪时,内核会通知用户进程进行IO操作。相比于阻塞IO和非阻塞IO,IO复用可以同时监听多个文件描述符,提高了IO效率。
  • 信号驱动IO是指用户进程通过signal或sigaction系统调用来注册一个信号处理函数,当IO操作完成时,内核会向用户进程发送一个SIGIO信号,用户进程在信号处理函数中进行IO操作。相比于阻塞IO和非阻塞IO,信号驱动IO可以避免用户进程被阻塞,提高了IO效率。
  • 异步IO是指当用户进程发起一个IO请求后,内核会立即返回,表示IO操作已经开始。当IO操作完成后,内核会通知用户进程,用户进程在此时才进行IO操作。相比于其他IO模型,异步IO可China编程以避免用户进程被阻塞,提高了IO效率。

2.五种IO模型

2.1 IO模型分析方法

分析IO模型需要了解2个问题:

问题1:发送IO请求,IO请求可以理解为用户空间和内核空间数据同步,根据发起者不同分为以下两种情况:

  • 由用户程序发起(同步IO)。
  • 由内核发起(异步IO)。

问题2:等待数据到来,等待数据到来的方式有以下几种:

  • 阻塞(阻塞IO)。
  • 轮询(非阻塞IO)。
  • 信号通知(信号驱动IO)。

Linux五种IO模型的使用解读

(内核空间和用户空间数据同步由谁发起是分析Linux IO模型最核心问题)

2.2 阻塞IO

Linux五种IO模型的使用解读

阻塞IO/阶段1

  • 用户程序调用recv函数发起IO请求(同步IO),读取socket缓冲区数据。
  • 由于socket缓冲区没有就绪数据包,进程状态将从TASK_RUNNING切换至TASK_INTERRUPTIBLE状态,并通过进程调度完成进程阻塞。
  • 同时进程也会加入到socket等待队列,等待数据到来回被唤醒。

注意:阻塞IO并不是阻塞CPU,而是进行进程状态切换出让CPU。

Linux五种IO模型的使用解读

阻塞IO/阶段2

  • 网卡收到数据包后,通过DMA机制将数据包拷贝到内核空间RingBuffer,并通过中断机制将数据包拷贝至socket接收缓冲区.
  • socket接收到数据包唤醒等待队列休眠进程,进程被唤醒后继续完成用户空间和内核空间数据同步,recv函数成功返回。

2.3 非阻塞IO

Linux五种IO模型的使用解读

阻塞IO/阶段1

  • 用户程序调用recv函数发起IO请求,读取socket缓冲区数据。
  • 由于socket缓冲区没有就绪数据包,非阻塞IO recv直接返回EWOULDblock错误码,用户如果一直调用recv函数则一直返回EWOULDBLOCK错误码,直到数据准备好。

非阻塞IO/阶段2

非阻塞IO和阻塞IO阶段2相同。

2.4 IO复用

IO复用简介

IO复用是一种高效的IO处理方式,它可以让一个进程同时监视多个文件描述符,当其中任意一个文件描述符就绪时,就可以进行相应的IO操作。

相比于传统的阻塞IO和非阻塞IO,IO复用可以大大提高IO效率,减少CPU资源的浪费。

在Linux中,常用的IO复用模型有select、poll、epoll等。

IO复用模型IO请求由用户程序发起,所以IO复用模型为同步IO。

2.4.1 IO复用select模型

Linux五种IO模型的使用解读

select模型通过位图实现IO复用,将socket注册到读,写,或异常位图,通过select系统调用轮询位图,获取socket事件,成功获取到socket事件后,select成功返回,此时可以通过接收函数读取socket缓冲区数据。

2.4.2 IO复用poll模型

Linux五种IO模型的使用解读

poll模型和select非常相似,主要区别为poll模型把位图改成链表,poll通过链表实现IO复用,将socket注册poll_list链表,通过poll系统调用轮询链表,获取socket事件,成功获取到socket事件后,poll成功返回,此时可以通过接收函数读取socket缓冲区数据。http://www.chinasem.cn

2.4.3 IO复用epoll模型

Linux五种IO模型的使用解读

epoll模式采用回调方式获取就绪socket事件,相比于select和poll模型的轮询方式效率更高,通过epoll_ctl系统调用注册socket事件至红黑树,当socket接收到数据后通过回调函数将http://www.chinasem.cnsocket事件添加至就绪队列,调用epoll_wait查询就绪队列就能获取到socket事件。

2.5 信号驱动IO

Linux五种IO模型的使用解读

信号驱动IO是基于SIGIO信号实现。

信号驱动IO主要由三个步骤组成:

  • 步骤1:用户程序注册SIGIO处理函数。
  • 步骤2:内核收到数据后,发送SIGO信号,执行SIGO信号处理函数。
  • 步骤3:用户程序调用recv函数发起IO请求,完成用户空间和内核空间数据同步。

信号驱动IO是由用户程序发起IO请求,所以信号驱动IO属于同步IO。

2.6 异步IO

Linux五种IO模型的使用解读

异步IO实现的方式有很多种,上图以POISX aio为例讲解异步IO。

分析异步IO我们得抓住本质,异步IO的IO请求由内核发起,只要满足这一个点就是异步IO,不管是阻塞或者轮询,或者信号通知,都不影响异步IO这个性质。

3.IO模型常见问题?

问题1:阻塞IO和非阻塞IO区别?

a.阻塞IO

阻塞IO在没有数据包时,会通过阻塞进程等待数据到来,阻塞进程方法为:

  • 设置进程状态为TASK_INTERRUPTIBLE。
  • 通过进程调度切换进程,实现进程阻塞。

进程阻塞期间不会占用CPU资源。

b.非阻塞IO

非阻塞IO在没有数据包时,通过轮询方式等待数据包到来,没有数据包到来,调用接收函数会立即返回EWOULDBLOCK错误码,一直调用接收www.chinasem.cn函数,一直返回EWOULDBLOCK错误码。

非阻塞方式采用轮询方式会一直占用CPU资源。

问题2:同步IO和异步IO区别?

区别同步IO和异步IO方法很简单,就是用户空间和内核空间数据同步由谁发起。

  • 由用户程序发起则是同步IO。
  • 由内核发起则是异步IO。

问题3:信号驱动IO和异步IO区别?

信号驱动IO和异步IO虽然实现流程有很多相似的地方,比如:注册信号处理函数,发送oyBMt通知信号,不会阻塞进程等。

信号驱动IO和异步IO有以下几点区别:

  • 信号驱动IO属于同步IO。
  • 信号驱动IO发送信号通知用户程序发起IO请求。
  • 异步IO发送信号通知用户程序IO请求已由内核发起并完成。

问题4:非阻塞IO是不是异步IO?

很多同学经常把非阻塞IO和异步IO关联在一起,其实这个是很错误的一个想法,同步IO和异步IO都可能会阻塞进程,同步IO和异步IO本质区别为用户空间和内核空间数据同步由谁发起。

非阻塞IO的IO请求由用户程序发起,属于同步IO。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程China编程(www.chinasem.cn)。

这篇关于Linux五种IO模型的使用解读的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155993

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res