IO - 阻塞/非阻塞/同步/异步 区别

下文是基于Linux网络IO展开的描述

操作系统用户态/内核态

  • 用户态:也称为用户空间,即上层应用程序的活动空间,应用程序的执行必须依赖于内核提供的资源。
  • 内核态:也称为内核空间,控制计算机硬件资源,并提供上层应用程序运行的环境

用户态可以通过系统调用切换到内核态,这是主动进入内核态的形式;

在出现异常或者外设中断时也会进入到内核态,这个是被动响应的形式。

IO模型可以区分为两个阶段

  1. 第一阶段:等待数据准备就绪
  2. 第二阶段:将数据从内核态拷贝到用户态

各种IO模型其实是根据以上两个阶段的不同表现来区分的(用户进程或线程是否阻塞)

  • 第一个阶段用户进程是否阻塞来区分 阻塞/非阻塞
  • 第二个阶段用户进程是否阻塞来区分 同步/异步

阻塞IO

当用户进程发起系统调用 recvform 时,

在第一阶段,内核首先会等待数据准备就绪,这个过程中用户进程是阻塞的;

在第二阶段,当数据准备就绪之后,数据会从内核空间拷贝到用户空间(应用程序空间),这个过程中用户进程同样是阻塞的,知道数据拷贝完成才恢复。

应用程序阻塞期间被挂起,进程从运行状态变为阻塞状态,让出CPU,当数据拷贝完成时,会通知进程,进程再进入到就绪状态,等待CPU的调度。

因此,阻塞IO在两个阶段都是阻塞的

非阻塞IO

非阻塞IO与阻塞IO相似,区别在于:

第一个阶段,在等待数据准备的过程中,用户进程不会阻塞,而是在数据没有准备就绪的时候得到一个error返回,这时用户进程就会知道数据还没有准备好,然后就继续发起 recvfrom 操作知道数据准备就绪(一直占用CPU,减少了进程/线程切换的开销)

第二个阶段,数据从内核空间拷贝到用户空间时,非阻塞IO用户进程同样是阻塞的(让出CPU)

因此,非阻塞IO是指在一个阶段不阻塞,第二个阶段阻塞

IO多路复用

IO多路复用,是通过 select/epoll 等函数轮询多个 socket,当用户进程调用了 select函数,整个用户进程就会被阻塞,直到收到数据准备就绪的返回。

后续操作和非阻塞IO相识,由于在 recvfrom 系统调用之前,需要的数据就已经准备好了,所以第一个阶段是非阻塞;第二个阶段还是阻塞。

因此,IO多路复用整个过程中,用户进程都是阻塞的

异步IO

异步IO是指用户进程发起read操作后,会立即收到一个返回,所以用户进程就可以去完成其他的工作了,从而不需要阻塞;

直到数据准备就绪并且完成了从内核空间拷贝到用户空间的工作,这时用户进程会收到一个通知,告诉它read操作已完成

因此,异步IO整个过程中用户进程不会被阻塞

总结

实际上 阻塞IO 和 非阻塞IO 都是 同步IO,用了特殊的异步函数才是异步IO

阻塞和异步没有直接关系,网上很多阻塞同步异步一起说,容易让人产生误解,认为阻塞/非阻塞和同步/异步有什么关联。

参考博客:https://juejin.im/post/6873688839622230029

posted @ 2020-09-27 15:45  它山之玉  阅读(458)  评论(0编辑  收藏  举报