最近逛论坛在知乎看到一篇非常不错的文章,遂收藏,分享给大家
又加深了对io模型的理解
知乎一篇文章:深入理解Linux的五种IO模型
Linux的五种IO模型
阻塞I/O (Blocking I/O)
• 特点:进程在数据准备和拷贝阶段均被挂起,直到操作完成
• 流程:
- 调用
recvfrom()
后线程阻塞 - 内核等待数据到达内核缓冲区
- 数据从内核空间拷贝到用户空间
- 函数返回成功
• 优点:实现简单,适合低并发场景
• 缺点:每个连接需独立线程/进程,资源消耗大
非阻塞I/O (Non-blocking I/O)
• 特点:立即返回EWOULDBLOCK
错误码,需轮询检查状态
• 流程:
- 调用
recvfrom()
立即返回(无数据时返回错误) - 进程持续轮询检查数据状态
- 数据就绪后完成拷贝
• 优点:避免线程阻塞
• 缺点:CPU空转消耗高,实时性差
I/O多路复用 (I/O Multiplexing)
• 核心机制:通过select/poll/epoll
监控多个文件描述符
• 工作流程:
- 将多个fd注册到监听集合
- 调用
select()
阻塞等待任一fd就绪 - 遍历就绪fd进行数据读写
• 技术对比:
• select
:位图管理,有1024fd限制
• poll
:链表实现,无数量限制
• epoll
:回调机制,性能最优
• 优点:单线程处理多连接,高并发场景首选
信号驱动I/O (Signal-driven I/O)
• 原理:通过SIGIO
信号通知数据就绪
• 流程:
- 注册信号处理函数(如
sigaction
) - 内核发送
SIGIO
信号通知数据就绪 - 在信号处理函数中调用
recvfrom()
• 优点:避免轮询消耗
• 缺点:信号处理复杂,TCP适用性有限
异步I/O (Asynchronous I/O)
• 核心特征:内核完成全部操作后通知进程
• 流程:
- 调用
aio_read()
立即返回 - 内核自主完成数据准备和拷贝
- 通过回调或信号通知进程
• 与同步I/O的本质区别:数据拷贝由内核发起
• 优点:完全非阻塞,性能最高
• 缺点:实现复杂,需内核支持(Linux 2.6+)
关键对比
模型 | 等待阶段是否阻塞 | 拷贝阶段是否阻塞 | 触发方式 |
---|---|---|---|
阻塞I/O | 是 | 是 | 同步 |
非阻塞I/O | 否(轮询) | 是 | 同步 |
I/O多路复用 | 是(select阻塞) | 是 | 同步 |
信号驱动I/O | 否 | 是 | 同步(信号) |
异步I/O | 否 | 否 | 异步 |
典型应用场景
• 阻塞I/O:简单客户端工具
• epoll多路复用:Nginx/Redis等高并发服务器
• 异步I/O:大规模存储系统(如数据库)