首先咱们来看一下这五种I/O分别是什么:阻塞I/O,非阻塞I/O,I/O复用,信号驱动I/O,异步I/O
异步
在来看下它们的执行过程(除异步I/O):都是分为两步,首先是等待数据准备(除信号驱动IO外,其它几种都是本身在等待),当数据准备好以后再有内核拷贝到咱们的用户空间。async
1. 阻塞I/O模型 ide
应用程序调用一个IO函数,致使应用程序阻塞,等待数据准备好。函数
若是数据没有准备好,一直等待。 测试
数据准备好了,从内核拷贝到用户空间 spa
IO函数返回成功指示线程
2. 非阻塞I/O模型 3d
咱们把一个套接口设置为非阻塞就是告诉内核,当所请求的I/O操做没法完成时,不要将进程睡眠(或挂起),而是返回一个错误。这样咱们的I/O操做函数将不断的测试数据是否已经准备好,若是没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程当中,会大量的占用CPU的时间。其中红色圈出来的过程就是不断在测试数据是否准备好了,当咱们看到数据准备好,则从内核拷贝到用户,而后返回成功。 指针
3. I/O复用
xml
I/O复用模型会用到select或者poll函数,这两个函数也会使进程阻塞,可是和阻塞I/O所不一样的的,这两个函数能够同时阻塞多个I/O操做。并且能够同时对多个读操做,多个写操做的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操做函数。
上层应用程序调用select(该机制由Linux内核支持,避免了Application3忙等待),进行轮询文件描述符的状态变化。当select管理的文件描述符没有数据(或者状态没有变化时),上层应用程序也会阻塞;select机制能够管理多个文件描述符;select能够当作一个管理者,用select来管理多个IO。
一旦检测到的一个I/O或者多个IO,有咱们监视的事件发生时,select函数将返回,返回值为检测到的事件个数,进而能够利用select相关API函数,操做具体事件;select函数能够设置等待时间,避免了上层应用程序长期僵死;和阻塞IO模型相比,selectI/O复用模型至关于提早阻塞了。等到有数据到来时,再调用recv就不会发生阻塞。
4. 信号驱动I/O模型
首先咱们容许套接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,能够在信号处理函数中调用I/O操做函数处理数据。、
这种用于模型用的比较少,属于典型的“拉模式(上层应用被动的去Linux内核空间中拉数据)”。即:上层应用须要调用recv函数把数据拉进来,会有时间延迟,咱们没法避免在延迟时,会又有新的信号的产生。
调用aio_read函数,告诉内核描述字,缓冲区指针,缓冲区大小,文件偏移以及通知的方式,而后当即返回。当内核将数据拷贝到缓冲区后,再通知应用程序。
说明1:上层应用程序调用aio_read函数,同时提交一个应用层的缓冲区buf;调用完毕后,不会阻塞。上层应用程序能够继续其余任务。
说明2:当TCP/IP协议缓冲区有数据时,Linux主动的把内核数据copy到用户空间。而后再给上层应用发送信号;告诉上层应用数据到来,须要处理!
说明3:典型的“推模式”
说明4: 效率最高的一种模式,上层应用程序Application5有异步处理的能力(在Linux内核的支持下,处理其余任务的同时,也可支持IO通信)。
下来咱们来了解一些关于阻塞与非阻塞的,及同步与异步的相关知识。
1. 阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态,阻塞调用是指调用结果返回以前,当前线程会被挂起。调用线程只有在获得结果以后才会返回。非阻塞调用指在不能马上获得结果以前,该调用不会阻塞当前线程。
2.同步与异步
同步和异步关注的是消息通讯机制 (synchronous communication/ asynchronous communication)所谓同步,就是在发出一个*调用*时,在没有获得结果以前,该*调用* 就不返回。可是一旦调用返回,就获得返回值了。 换句话说,就是由*调用者*主动等待这个*调用*的结果。而异步则是相反,*调用*在发出以后,这个调用就直接返回了,因此没有返回结果。 换句话说,当一个异步过程调用发出后,调用者不会马上获得结果。而是在*调用*发 出后,*被调用者*经过状态、通知来通知调用者,或经过回调函数处理这个调用。
a. 同步I/O操做引发请求进程阻塞,直到I/O操做完成。
异步I/O操做不引发请求进程阻塞。
b. 咱们的前四个模型都是同步I/O,只有最后一个异步I/O模型是异步I/O。