博客
关于我
5种IO模型和IO多路复用详解
阅读量:302 次
发布时间:2019-03-01

本文共 2079 字,大约阅读时间需要 6 分钟。

I/O模型概述

  • 同步I/O
    • 阻塞式I/O
    • 非阻塞式I/O
    • I/O复用
    • 信号驱动I/O
  • 异步I/O
    • POSIX的异步 I/O 函数

输入操作流程

输入操作一般分为两个流程

  1. 等待数据准备好
    • 对于在套接字上的操作,就是等待数据在网络中到达内核缓冲区
  2. 从内核向进程中复制数据
    • 就是把数据从内核缓冲区中复制到应用进程缓冲区

同步I/O和异步I/O的区别

同步 I/O 操作导致请求进程阻塞

异步 I/O 操作不导致请求进程阻塞

阻塞式 I/O 、非阻塞式 I/O 、I/O 复用、信号驱动 I/O 都是同步 I/O,因为在输入流程的第二步上都会将进程阻塞,

而异步 I/O 模型只有 POSIX 定义的异步 I/O 与之相匹配

5种I/O模型

阻塞式I/O

在这里插入图片描述

调用recvfrom函数后用户进程会阻塞等待数据到达内核缓冲区并且拷贝到应用进程缓冲区后返回

非阻塞式I/O

1483366389700024047.png

循环调用recvfrom函数,如果数据没到达内核缓冲区就立即返回一个错误,如果数据到达了就复制数据到应用进程缓冲区(循环调用的过程叫轮询

I/O复用

1483366448898081321.png

I/O 复用又叫 I/O 多路复用

I/O 复用模型下应用进程会被阻塞两次,分别对应输入流程的两个步骤,

  1. 第一部分调用 select 函数阻塞直到数据在内核中准备好,函数返回;(I/O 多路复用中不仅仅只有 select,还有 poll 和 epoll)
  2. 第二部分调用 recvfrom 函数把数据复制到应用进程的缓冲区

I/O 多路复用和其他的 I/O 模型不同在他可以一次追踪多个 I/O 流,I/O 复用是在单线程下追踪多个 I/O 流,与他相似的是在多线程下,每个线程追踪一个 I/O 流

信号驱动I/O

1483366503112041652

首先开启套接字的信号驱动 I/O 功能,相当于调用函数告诉内核接收到数据时传递信号给应用进程,然后应用进程就可以在信号处理函数中调用recvfrom从内核中读取数据,或者通知主循环读取,和 I/O 复用的是在第一部分也就是建立信号处理程序是直接返回的,是不会阻塞应用进程的

异步I/O

异步 I/O 由POSIX规范定义,工作方式是直接将输入流程的两个部分都交给内核完成,通过调用 aio_read 函数(传递文件描述符,缓冲区指针,缓冲区大小等),调用后直接返回,让内核接收到数据并且把数据复制到应用程序的缓冲区(传入的缓冲区指针)后发送信号给应用进程,进程在对应的信号处理程序中处理数据

图片引用自:

I/O 多路复用的 select/poll/epoll 详解

以下内容需要再考证

select

select 函数参数主要有文件描述符的数组,以及一个32个整数大小的bitmap(1024位)

调用 select 后,内核会先把文件描述符数组复制到内核中,内核会查看每一个文件描述符是否有数据到达,到了就会把bitmap置位,完成后然后返回,(这期间阻塞应用进程),应用进程遍历文件描述符,通过bitmap就可以知道数据是否到达并调用 recvfrom 来读取数据到进程的缓冲区中

复制到内核中交给内核遍历判断的好处是避免频繁在用户态和内核态间切换,速度更快,因为如果是应用进程直接遍历判断还是需要切换到内核态的,切换是需要额外开销的

select

缺点:

  1. bitmap大小1024位,最多支持追踪1024个 I/O 流
  2. bitmap置位后导致下一次循环中不能重用,需要下一次循环开始时重新遍历设置
  3. 文件描述符拷贝到内核态会额外开销
  4. select 返回后还是需要遍历每个文件描述符判断一遍,O(n)

poll

struct pollfd{   	int fd;//文件描述符    short events;//读写事件    short revents;//用于置位}

调用 poll 函数,参数主要是 pollfd 数组(充当 select 函数中的文件描述符数组和位图功能),同样会复制文件描述符数组到内核,但是使用了 revent 置位,函数返回后,用户进程遍历文件描述符时,发现 revent 被置位了,进行读取数据并将 revent 字段复位

poll.png

优点:

  1. 解决了文件描述符上限问题
  2. 解决了bitmap被置位后不可重用的问题

缺点:

  1. 文件描述符数组拷贝到内核态会额外开销
  2. poll 返回后还是需要遍历每个文件描述符判断一遍,O(n)

epoll

epfd 类似 pollfd 有 fd 和 events 字段(似乎是一个双向链表(待考究))

不需要拷贝 epfd 到内核态,并且 epoll 会把 epfd 重新排序,把有数据的文件描述符排到头部,返回一个整数代表有数据的文件描述符数量,应用进程遍历时就不需要用 O(n) 的复杂度遍历了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3huT5pn-1619186298656)(D:\Desktop\note\linux与操作系统\epoll.png)]

优点:

  1. 解决拷贝文件描述符的开销
  2. 解决了函数返回后 O(n) 的遍历复杂度,复杂度O(1)

转载地址:http://ytio.baihongyu.com/

你可能感兴趣的文章
multivariate_normal TypeError: ufunc ‘add‘ output (typecode ‘O‘) could not be coerced to provided……
查看>>
MySQL DBA 数据库优化策略
查看>>
multi_index_container
查看>>
MySQL DBA 进阶知识详解
查看>>
Mura CMS processAsyncObject SQL注入漏洞复现(CVE-2024-32640)
查看>>
Mysql DBA 高级运维学习之路-DQL语句之select知识讲解
查看>>
mysql deadlock found when trying to get lock暴力解决
查看>>
MuseTalk如何生成高质量视频(使用技巧)
查看>>
mutiplemap 总结
查看>>
MySQL DELETE 表别名问题
查看>>
MySQL Error Handling in Stored Procedures---转载
查看>>
MVC 区域功能
查看>>
MySQL FEDERATED 提示
查看>>
mysql generic安装_MySQL 5.6 Generic Binary安装与配置_MySQL
查看>>
Mysql group by
查看>>
MySQL I 有福啦,窗口函数大大提高了取数的效率!
查看>>
mysql id自动增长 初始值 Mysql重置auto_increment初始值
查看>>
MySQL in 太多过慢的 3 种解决方案
查看>>
MySQL InnoDB 三大文件日志,看完秒懂
查看>>
Mysql InnoDB 数据更新导致锁表
查看>>