IO模型
同步、异步、阻塞、非阻塞
socket阻塞与非阻塞,同步与异步
同步和异步
同步/异步主要针对C端
-同步
就像普通的页面,在页面发送post过去之后,到收到页面返回的信息。这整一个动作是同步的
-异步
浏览器如果是通过ajax和服务器进行交互的。这个步骤就是异步的。
同步IO和异步IO的区别在于:数据访问的时候进程是否阻塞
阻塞和非阻塞
-阻塞
用户向Web服务器发送一个请求,web服务器向数据库请求这个请求,然后一直等数据库返回结果,在得到结果后讲数据返回给用户。
-非阻塞
一个用户向Web服务器发送一个请求,Web服务器告诉数据库我要一个什么样的东西,然后Web服务器做其他的事情,数据库完成之后告诉(通知、回调、状态)Web服务器,Web回来接受讯息,然后把结果返回给用户。
阻塞IO和非阻塞IO的区别在于:应用程序的调用是否立即返回
-阻塞I/O
-非阻塞I/O
-I/O复用
-信号驱动I/O
-异步I/O
前四种都是同步,只有最后一种是异步。
阻塞I/O模型
进程会一直阻塞,直到数据拷贝完成
进程挂起,阻塞整个I/O
大伯等邮件 邮递员没有来就一直等
非阻塞I/O模型
非阻塞IO通过进程反复调用IO函数
采用轮询,占用CPU
大伯跑到一楼后发现没有新邮件,他便跑回自己的住房,然后又跑下来看有没有新邮件,没有的话又跑回去…如此反复的爬上爬下直到有新的邮件来为止
I/O复用
主要是select和epoll,对一个IO端口,两次调用,两次返回,和阻塞IO相比没有什么优越性,能实现对多个IO端口进行监听。
多个连接共用一个等待机制
好比一个小区的邮件收发室,当有新的邮件到达时,值班员会通知响应的人来领取这个邮件。
信号驱动IO模型
首先开启套接口信号驱动IO功能,通过系统调用sigation执行一个信号处理函数(此信号调用直接返回,进程继续工作)。当数据准备就绪时,生成一个signal信号,通知应用程序来取数据。
异步IO
告知内核启动某个操作,并让内核在整个操作完成的的那个之后(将数据从内核复制到用户自己的缓冲区),进行通知
和信号驱动模型的主要区别室:信号驱动IO由内核通知我们合适可以开始一个IO操作在client进行IO操作的时候需要等待,所以是同步的。异步IO模型由内核通知我们IO何时已经完成,client不需要进行IO的处理了,所以是异步的。
别人的总结
阻塞IO
这是我们熟悉的IO模型,一个进程在作IO操作时,非要等到数据从内核空间拷贝到用户进程空间,才会返回。这个模型的优点就是简单,而且在阻塞的时候,CPU还可以进行调度,去执行别的进程。
非阻塞IO
一开始我看是非阻塞IO,觉得应该要比阻塞IO模型先进,可是当我一看使用方法的时候,就知道这个模型是不会被实际使用的,仅仅只能作为理论上存在的IO模型。这个模型的观点是:进行IO操作的时候,不阻塞,如果没有数据准备好,就直接返回错误码(或者是别的代码)。因此,使用者就只能不断进行轮询来调用IO函数。这样的后果就是,不仅在宏观上形成了与阻塞IO一共的“阻塞”效果,而且在微观上,CPU一直被用来轮询,造成了CPU的浪费。所以,这个模型还不如阻塞IO模型实用。
IO复用
对于IO复用,我的理解有三点:
在一次系统调用中,实现了询问多个描述符的IO准备情况 —— 根据事件通知
为了实现第一点,就需要把阻塞的地方进行转移。把一次系统调用,分为两次系统调用。第一次系统调用可以询问多个描述符的IO准备情况,在这个地方进行阻塞;而第二次系统调用,是针对已经准备好IO的描述符进行调用,此时,理论上(按照我的理解),也是会发生阻塞的,只不过是此时内核已经把数据准备好了,阻塞的时间可以忽略不计罢了。
本质上,还是阻塞的。
信号IO
我们都知道,信号是UNIX提供了进程间进行通信的一种方式。我们常用的 kill -9 命令(kill是向进程传递信号量,9只是众多信号中的一个代号),或者是 Ctrl + C 的时候,就是向某个进程发出终止的信号,这样进程就退出了。
而对于信号IO的模型,我是这么理解的:进程在发起IO操作,系统调用之后,直接访问,内核会在IO数据准备好之后,以某个信号通知发起IO操作的进程,从而使得该进程的信号处理函数可以读取IO数据的操作。
本质上,这也是阻塞的IO模型,因为在信号处理函数中,同样也是要进行阻塞的,只是在在这个时候发起系统系统,内核已经把数据准备好了。
异步IO
这是真正的异步IO了。实现的机制是:用户在发起异步IO的系统调用时,会把相应的数据处理函数作为回调函数,等到IO数据准备好,内核会主动调用此回调函数。可以看出,用户进程在这种模型下,只调用了一次系统调用,而且是立即返回的,因此,就不会出现让进程阻塞的情况,也就符合了POSIX中异步IO的定义。
其实我理解起来,思路是和信号IO差不多的,唯一不同的地方,对于IO数据的操作,异步IO是由内核主动发起的,而信号IO是由用户进程发起的。