linux 五种 IO 模型

本文详细探讨了同步与异步任务执行的区别,阻塞与非阻塞状态在IO中的应用,以及数据在socket间的两次拷贝。重点介绍了同步阻塞IO、同步非阻塞IO、IO多路复用(NIO)和信号驱动IO模型,并对比了它们的特点。

一. 同步异步,阻塞非阻塞与数据二次拷贝

1. 同步异步: 任务的执行顺序上区分
  • 同步: 指一个任务, 只有当另一个任务返回后才能继续执行本任务
  • 异步: 指一个任务只是发起一个通知告诉另一个任务可以执行了, 然后就继续执行自身的任务

同步可以保证2个任务的执行顺序, 而异步不能

2. 阻塞和非阻塞: 线程等待状态上区分
  • 阻塞: 一个线程如果在等待另一个线程返回时, 自身处于挂起状态, 就是阻塞的
  • 非阻塞: 反之则是非阻塞
3. 同步阻塞和同步非阻塞

同步表示必须保证任务顺序, 阻塞表示线程等待另一个线程时是否会被挂起, 因此:

  • 同步非阻塞: 一个线程必须等待一个方法调用完毕才能继续执行接下来的任务, 且在等待过程中还可以执行其他方法, 则是同步非阻塞的
  • 同步阻塞: 一个线程必须等待一个方法调用完毕才能继续执行接下来的任务, 但是等待过程中自己处于挂起状态, 则是同步阻塞的
4. 数据由 socket 设备到用户态经过两次拷贝

用户进程在读/写外存(socket 设备)上的数据时, 数据先从 socket 拷贝到内核空间, 然后再从内核空间拷贝到用户空间.

二. Linux IO模型

IO 模型是针对, 数据从 socket 到内核空间, 再到用户空间这两次拷贝过程中, 用户线程的状态

同步IO模型

如下各种同步阻塞 IO 模型, 第二步 内核空间->内核空间 的数据拷贝都是阻塞的, 通过阻塞的方式, 实现数据拷贝和用户进程使用的同步

1. 同步阻塞IO

同步阻塞IO, 数据拷贝的两个阶段 (socket -> 内核, 内核 -> 用户)中, 用户进程都是处于阻塞状态.
在这里插入图片描述

2. 同步非阻塞IO

socket被设置成非阻塞的后

  • socket -> 内核空间 : 用户进程不会阻塞 (轮训操作系统)
    如果内核空间数据未拷贝完, 操作系统返回给用户进程一个错误码, 表示数据还未准备好. 此后用户进程要轮训询问操作系统数据拷贝进度.
  • 内核空间 -> 用户空间 : 用户进程阻塞
    数据到内核空间复制完毕后, 用户进程进入阻塞, 等待数据从内核空间复制到用户空间

所以,nonblocking IO的特点是用户进程需要不断的轮训询问kernel数据好了没有。
在这里插入图片描述

3. IO多路复用(NIO)

IO多路复用将同步非阻塞 IO 的到内核态拷贝中, 用户进行轮训操作系统改为操作系统自动轮训查看 socket 数据是否拷贝完毕, 且可以同时轮训多个 socket. (epool)
前置知识: 每个 socket 连接, 在 Linux 系统中会被表示成一个文件描述符(fd)
IO多路复用过程如下:

  1. socket -> 内接空间 (用户进程阻塞, 但可以提前返回, 且不必自己轮训拷贝状态)
    • 用户进程调用 select 系统调用后进入阻塞状态
    • 操作系统开始轮训所有 socket fd, 当]一个 socket fd 的数据可读/可写后(不用等到数据完全拷贝到内核空间), 在该 socket fd 上的 select 调用就会返回
  2. 内核空间 -> 用户空间 (用户进程阻塞)
    用户进程在 select 调用返回后变成就绪状态. 接着进行 recvFrom 调用, 将数据从内核空间拷贝到用户空间

IO多路复用主要解决服务器同时存在大量连接的情况, 是单线程处理多连接的模型;
在这里插入图片描述

上面提到的 select 和 epoll 主要有以下几个区别:

  1. select 的文件句柄数受限制, 最多能监听1024个 fd, 而 epoll 的 fd 个数没有限制
  2. select 采用轮训, fd 形成一个类似数组的结构. epoll 采用队列的数据结构, 对于是否有 fd 可读或可写, 直接查看对应的队列是否为空即可. 这是因为epoll只会对"活跃"的socket进行操作, 每个fd上配置一个回调函数, 只有fd可读或可写时才会出发回调函数(将自己加入相应的队列中), 其他idle状态句柄则不会,在这点上,epoll实现了一个"伪"AIO
  3. epool使用 mmap 加速内核与用户空间的消息传递。
    无论是 select,poll 还是 epoll 都需要内核把 FD 消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。
4. 信号驱动IO
  • socket -> 内核空间 (用户进程非阻塞)
    信号驱动式 I/O 第一步采用在 socket 上注册回调函数(信号处理函数)的方式, 让操作系统自行拷贝. 用户进程在此期间并不阻塞。当数据准备好时,进程会收到一个 SIGIO 信号,可以在信号处理函数中调用 IO 操作函数处理数据。
  • 内核空间 -> 用户空间 (用户进程阻塞)
    在这里插入图片描述
异步IO模型
5. 异步非阻塞IO(AIO)

第一步和第二步, 用户进程都是非阻塞的
异步非阻塞 IO 是说, 用户发起 aio_read 操作之后, 函数立刻返回, 用户进程开始做其它工作, socket 数据复制到内核空间, 和内核空间复制到用户空间这两个步骤都是操作系统完成的. 两步完成后, 操作系统会给用户进程发送一个 signal 或执行一个基于线程的回调函数来完成这次 IO 处理过程,告诉它 read 操作完成了.
在这里插入图片描述

总结: 几种IO之间的区别

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值