【操作系统】|浅谈IO模型

I/O(Input/Output)指的是应用程序与外部环境之间的数据交换。I/O 操作涉及从外部设备(如硬盘、网络、键盘、鼠标等)读取数据或向外部设备写入数据。

操作系统启动后,将会开启保护模式:将内存分为内核空间(内核对应进程所在内存空间)和用户空间,进行内存隔离。我们构建的程序将运行在用户空间,用户空间无法操作内核空间,也就意味着用户空间的程序不能直接访问由内核管理的I/O。

操作系统向外提供API,其由各种类型的系统调用(System Call)组成,以提供安全的访问控制。应用程序通过向内核发起系统调用完成对I/O的间接访问,故一次IO操作实际包含两个阶段:

  • IO调用阶段:应用程序进程向内核发起系统调用
  • IO执行阶段:内核执行IO操作并返回
      1.准备数据阶段:内核等待I/O设备准备好数据
      2. 拷贝数据阶段:将数据从内核缓冲区拷贝到用户空间缓冲区

【操作系统】|浅谈IO模型_第1张图片

阻塞IO / BIO

应用程序中进程在发起IO调用后至内核执行IO操作返回结果之前,若发起系统调用的线程一直处于等待状态。

BIO带来了一个问题:如果内核数据需要耗时很久才能准备好,那么用户进程将被阻塞,浪费性能。为了提升应用的性能,虽然可以通过多线程来提升性能,但线程的创建依然会借助系统调用,同时多线程会导致频繁的线程上下文的切换,同样会影响性能。

非阻塞IO / NIO

将阻塞变为非阻塞,那就是用户进程在发起系统调用时指定为非阻塞,内核接收到请求后,就会立即返回,然后用户进程通过轮询的方式来拉取处理结果。

【操作系统】|浅谈IO模型_第2张图片

非阻塞IO虽然相对于阻塞IO大幅提升了性能,其依然存在性能问题,也就是频繁的轮询导致频繁的系统调用,会耗费大量的CPU资源。比如当并发很高时,假设有1000个并发,那么单位时间循环内将会有1000次系统调用去轮询执行结果,而实际上可能只有2个请求结果执行完毕,这就会有998次无效的系统调用,造成严重的性能浪费。有问题就要解决,那NIO问题的本质就是频繁轮询导致的无效系统调用

I/O 多路复用
select/poll

Select是内核提供的系统调用,它支持一次查询多个系统调用的可用状态,当任意一个结果状态可用时就会返回,用户进程再发起一次系统调用进行数据读取。换句话说,就是NIO中N次的系统调用,借助Select,只需要发起一次系统调用就够了。

【操作系统】|浅谈IO模型_第3张图片

select有一个限制,就是存在连接数限制,针对于此,又提出了poll。其与select相比,主要是解决了连接限制。select/epoll 虽然解决了NIO重复无效系统调用用的问题,但同时又引入了新的问题。

  • 用户空间和内核空间之间,大量的数据拷贝
  • 内核循环遍历IO状态,浪费CPU时间
epoll

epoll相较于select/poll,多了两次系统调用,其中epoll_create建立与内核的连接,epoll_ctl注册事件,epoll_wait阻塞用户进程,等待IO事件。

【操作系统】|浅谈IO模型_第4张图片

【操作系统】|浅谈IO模型_第5张图片

信号驱动 I/O 
  • 在信号驱动模型中,程序告诉操作系统在 I/O 操作完成时发送一个信号给程序,程序可以在信号处理函数中处理完成的 I/O 操作。
  • 这样程序不需要一直轮询,但仍然需要处理信号。

异步 I/O / AIO

  • 在异步模型中,程序发起一个 I/O 操作后,可以继续执行其他任务,当 I/O 操作完成时,操作系统通知程序,程序再处理完成的数据。
  • 异步 I/O 模型通常需要使用回调函数或异步事件处理机制。

你可能感兴趣的:(面试问题集合,网络,经验分享,后端)