IO模型

同步和异步

同步

函数或方法被嗲用的时候,调用者是否得到最终结果

直接得到最终结果的,就是同步调用,

不直接得到最终结果的,就是异步调用

阻塞和非阻塞

函数与或方法调用的时候,是否立刻返回

立刻返回就是非阻塞调用

不立刻返回就是阻塞调用

注意:

同步,异步强调的是,是否得到(最终的结果)

阻塞,非阻塞敲掉的是时间,是否等待

IO模型

IO的两个阶段

  1. 数据准备阶段
  2. 内核空间赋值回用户进程缓冲区阶段(将数据从内核拷贝到进程中)]

同步IO包括:阻塞IO,非阻塞IO,IO多路复用

阻塞IO(blocking IO)

  1. 而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,
  2. 然后kernel返回结果,用户进程才解除block的状态,重新运行起来。

所以,blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了。

非阻塞IO(non-blocking IO)

进程调用read操作,如果IO设备没有准备好,立刻返回error,进程不阻塞.

用户可以再次发起系统调用,如果内核已经准备好,就阻塞,然后复制数据到用户空间

第一阶段是非阻塞的.

第二阶段是阻塞的,即内核空间和用户空间之间的赋值数据是阻塞的.

不建议使用,因为其缺点明显:

​ 循环使用recv()大幅度推高CPU占用,

​ 任务完成的响应延迟增大了,因为每过一段时间轮询一次read的操作,而任务可能在两次轮询之间的任意时间完成.

​ 会导致整体数据吞吐量的降低.

多路复用IO(IO multiplexing)

有些地方也称这种IO方式为事件驱动IO(event driven IO)。

就是同时监控多个IO,有一个准备好了,就直接返回

以select为例

  1. 当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,
  2. 当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
  3. 这个图和blocking IO的图其实并没有太大的不同,事实上还更差一些。因为这里需要使用两个系统调用\(select和recvfrom\),
  4. 而blocking IO只调用了一个系统调用\(recvfrom\)。但是,用select的优势在于它可以同时处理多个connection。

优点:

使用select()的事件驱动值使用单线程(进程)执行,占用资源少,不消耗太多CPU,可以同时服务多个连接

缺点:

该模型将事件探测和事件响应夹杂在一起,一旦事件响应的执行体过大,对整个模型是灾难性的

一般情况,select最多能监听1024个fd(文件描述符)(可以修改,但是不建议),但是由于select采用轮询的方式,当管理的IO多了,每次都要遍历全部fd,效率低下.相当于是,文件准备好了,再去遍历一边看看哪个好了,返回数据

epoll没有管理的fd的上限,且是回调机制,不需遍历,效率很高,相当于是文件准备好了,直接去调准备好的数据返回,

异步IO(Asynchronous I/O)

用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

不常用

Python中的IO多路复用

selectors库

posted @ 2019-10-25 20:15  Agsol  阅读(135)  评论(0编辑  收藏  举报