1,阻塞型IO:最简单的一种IO模型,简单来讲就是死等,即线程或进程一直等待某个条件,不满足则一直等待。
2,非阻塞型IO:应用进程与内核交互,目的未达到之前会直接返回,然后不断轮询,不停的去问内核数据是否准备好,如果发现准备好了,就把数据拷贝到用户空间。应用进程通过recvfrom调用不停的去和内核交互,直到内核准备好数据。如果没有准备好,内核会返回error,应用进程在得到error后,过一段时间再发送recvfrom请求。在两次发送请求的时间段,进程可以先去做其他的事情。
3,信号驱动IO:我们会发现非阻塞型IO方式一遍一遍的轮询不如等内核把数据准备好了,然后通知进程,当进程收到该通知后,便开始把数据拷贝到用户空间中。也就是说进程预先向内核注册一个信号处理函数,然后用户进程返回,并不阻塞,当内核数据准备好后就会发送一个信号给进程,用户进程便在信号处理函数中开始把数据拷贝到用户空间中。
4,IO复用型:顾名思义就是将多个进程注册到同一管道上,这里管道会同一和内核进行交互。当管道中的某一个请求需要好的数据准备好之后,进程再把对应的数据拷贝到用户空间中。IO多路复用是多了一个select函数,多个进程的IO可以注册到select中,用户调用select。select会监听所有注册好的IO,如果所有被监听的IO需要的数据都没有准备好,select调用会阻塞进程。当任意一个IO需要的数据准备好了后,select就会返回,然后进程再通过recvfrom函数接收数据拷贝,但是实际上,它并未向内核注册信号函数,所以它并不是非阻塞的。
以上的四种模型都是同步的,因为无论哪种以上哪种模型,真正的数据拷贝过程都是同步的(个人觉得,所有的数据拷贝过程都是用户进程进行的)
5,异步IO模型:应用进程把IO请求传给内核后,完全由内核去进行文件的拷贝工作,内核在完成操作后,会发信号告诉应用进程本次IO已经完成。用户发起read操作之后,给内核传递文件描述符,缓冲区指针和缓冲区大小等,告诉内核进程当整个操作完成时,如何通知进程,然后就去做其他事情了。当内核收到read事件后,会立刻返回,然后内核开始等待数据准备,数据准备好之后,直接把数据 拷贝到用户空间,然后通知进程本次IO已经完成。
在这里分别给这五个模型举一个小例子来帮助理解吧!
1,阻塞IO模型:假如我调用了买报纸这个函数,如果没有把报纸买回来,我就一直等,直到报纸买回来了我才会去做其他事情。
2,非阻塞IO模型:意思就是我调用买报纸这个函数,我不需要一直等报纸买回来,我可以先去做别的事情,但是每隔一段时间我都会去问一下内核我的报纸回来了没,如果回来了就通知我,我去取报纸(此过程依然是同步的)。
3,IO复用模型:假如我现在不只买一份报纸,我买了很多份报纸,我就告诉一个邮差(select,poll,epoll),让他帮我盯着点,如果有哪个报纸有货了就给我说一声,但是它只是通知我有货了,并没有把报纸直接给我送来,还是需要我自己去取的。
4,信号IO模型:我事先告诉卖报纸的,当这个报纸有货的时候就直接发信号给我,然后我去调用买报纸的函数。
5,异步IO模型:假如我现在需要买报纸了,我告诉卖报纸的老板,然后等他把报纸准备好放到我家门口并告诉我都准备好了。(异步)这个过程我从头到尾不需要去管。