I/O介绍
I/O通常有内存IO、网络I/O、磁盘I/O等,但我们通常说的是网络I/O以及磁盘I/O。网络I/O:本质是socket读取
每次I/O请求,都会有两个阶段组成: 第一步:等待数据,即数据从磁盘到内核内存;将数据从磁盘文件先加载到内核内存空间(缓冲区),等待数据准备完成,时间较长。第二步:复制数据,即数据内核内存到进程内存;将数据从内核缓冲复制到用户空间的进程内存中,时间较短。
Web请求处理过程
1.客户端发起情况到服务器网卡2.服务器网卡接受到请求后转交给内核处理3.内核根据请求对应的套接字,将请求交给工作在用户空间的Web服务器进程4.Web服务器进程根据用户请求,向内核进行系统调用,申请获取相应资源(如:客户端获取图片)5.内核发现Web服务器进程请求的是一个存放在本地硬盘上的资源,因此通过驱动程序连接磁盘6.内核调用磁盘,获取需要的资源7.内核将资源存放在自己的缓存区中,并通知Web服务器进程8.Web服务器进程通过系统调用取得资源,并将其复制到进程自己的缓冲区中9.Web服务器进程形成响应,通过系统调用再次发给内核以响应请求10.内核将响应发送至网卡11.网卡发送响应给用户
通过这样的一个复杂过程,一次请求就完成了
简单来说就是:
用户请求——》送达用户空间——〉系统调用——》内核空间——〉内核到磁盘上读取图片资源——》返回到用户空间——〉响应给用户
上述简单的说明了一下,客户端向Web服务器请求过程,在这个过程中,有两个I/O过程:一是客户端请求的网络I/O,二个是Web服务器请求图片磁盘I/O。
I/O模型名词介绍
说到I/O模型,都会牵扯到同步、异步、阻塞、非阻塞这几个词,以下讲解这几个词的概念。
阻塞和非阻塞
阻塞和非阻塞指的是执行一个操作时等操作结束再返回结果,还是马上返回结果。
阻塞(blocking):指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起(当前线程进入非可执行状态,在这个状态,CPU不会分配时间片,线程暂停运行)只有到到结果才进入活动状态;
阻塞例子:海底捞的服务器为你点菜,当你点完菜后,服务员把消息传到后厨,这时你就在餐桌上等待,直到厨师把汤锅和配菜都准备好以后送到你桌上,你才能开吃。在上菜的过程中你还不能离开,因为你离开了之后服务员上菜了却找不到你人,所以你就是能等待,这个时候你处于阻塞等待状态,就是前面说的,你是调用者,你被挂起了,进入了非可执行状态。
非阻塞(nonblocking):指I/O操作被调用后立即返回给用户一个状态值,无需等到I/O操作彻底完成,最终的调用结果返回之前,调用者不会被挂起;
非阻塞例子:海底捞的服务器为你点菜,当你点完菜后,服务员把消息传到后厨,过了三分钟,你跑到后厨问,我的锅底或者肥牛卷好了没有?后厨说没好,然后你去处理其它事情,然后又过了五分钟,你又跑到后厨问,我的某个菜好了没有,如果没有,你还是继续做其他事情,然后等会再问一次,这个时候就是在I/O操作的同时,你没有被挂起,可以操作其他事情,但是如果I/O操作完成,你需要立马接受。
同步和异步
同步/异步关注的是消息通信机制
同步(synchronous):调用者等待被调用者返回消息,才能继续执行。同步阻塞例子:去餐馆吃饭,点了一个盖浇饭,然后在餐桌上一直等到盖浇饭做好,自己端到餐桌就餐。这就是典型的同步阻塞。当厨师给你做饭的时候,你需要一直在那里等着。
同步非阻塞例子:去餐馆吃饭,点了一个盖浇饭,你点完饭之后,过了几分钟感觉时间差不多了,就去问老板饭做好了没有,如果好了就去端,如果没好等一会再去问,实时同步做饭进度,依次循环去问直到饭做好,这就是同步非阻塞。 异步(asynchronous):被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态。
I/O模型类型
IO模型分为以下五类
1.阻塞型:所有过程全阻塞2.非阻塞型:如果没有数据buffer,则立即返回EWOULDBLOCK3.I/O复用型(select和poll):在wait和copy阶段分别阻塞4.信号驱动型I/O(SIGIO):在wait阶段不阻塞,但copy阶段阻塞(信号驱动I/O),即通知5.异步I/O(AIO):完全无阻塞方式,当I/O完成时提供信号
阻塞I/O
说明:应用程序调用一个IO的recvfrom函数,会导致应用程序阻塞,进入阻塞状态后直到I/O操作结束才会返回;如果系统内核数据没有准备好,那就一直等待数据准备,因为是调用了recvfrom函数导致了应用程序阻塞,所以一直在等,做不了任何事情,内核数据准备好之后把数据从内核拷贝到用户空间,拷贝结束后,I/O函数返回成功指示。注:其阻塞时在I/O操作阶段
非阻塞I/O
说明:用户线程发起IO请求时立即返回。但并未读取到任何数据,则返回字段为“EWOULDBLOCK”,用户线程需要不断地发起IO请求,直到数据到达后,才真正读取到数据,继续执行。即“轮询”机制。整个IO请求过程中,虽然用户线程每次发起IO请求后可以立即返回,但是为了等到数据。仍需要不断地轮询、重复请求、消耗了大量的CPU资源;是比较浪费CPU的方式,一般很少用这种模型,而是在其他模型中使用非阻塞IO这一特性。
I/O复用(select和poll)
说明:I/O复用模型会用到select或poll函数,在I/O复用模型中,并不是阻塞到I/O操作过程中,而是阻塞到select或者poll函数中;以select为例:进程在select处阻塞,等待几个描述符中的一个变为可操作,如果没等待到就继续阻塞在第一阶段,如果等到了一个描述符变为了可操作,则调用recvfrom函数将数据拷贝到应用缓冲区。
信号驱动I/O(SIGIO)
说明:首先,我们允许套接口进行信号驱动I/O,并安装一个信号处理函数SIGIO,如果数据没有准备好,则立即返回结果,进程继续工作并不阻塞。当数据准备好时,系统内核会主动发送一个SIGIO信号给应用程序,应用程序收到信号后,可以在信号处理函数中调用I/O操作函数recvfrom进行数据处理。信号驱动I/O模型的优点是当数据报到达时,可以不阻塞,主循环可以继续执行,只是等待处理程序的通知,或者数据已经准备好被处理,或者数据报已经准备好被读了。
异步I/O(AIO)
说明:当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态通知和回调通知来告诉调用者的输入输出操作。用户可以直接对I/O执行读写操作,这些操作告诉内核用户读写缓冲区的位置,以及I/O操作完成之后内核通知应用程序的方式,就是上面讲的通过状态通知或者回调通知来告诉调用者。异步I/O的读写操作总是立即返回,但没有返回结果说是否阻塞,因为异步I/O操作真正的读写操作已由内核接管,内核自己对数据处理完成后生成一个信号,然后通知用户刚才交给自己的事件已经处理完成。
五种I/O模型的总结及比较
中文图示如下:
英文图示如下:
从两张图中我们可以看到,越往后,阻塞越少,理论上效率也是最优。其中五种I/O模型中,前三种属于同步I/O,后两者属于异步I/O。
同步I/O
阻塞I/O 非阻塞I/O I/O复用(select和poll)
异步I/O
信号驱动I/O(SIGIO) 半异步 异步I/O(AIO) 全异步
异步I/O和信号驱动I/O的区别
信号驱动I/O模式下,内核可以复制的时候通知给我们应用程序发送SIGIO信号。异步I/O模式下,内核在所有的操作由内核操作完成后才会通知我们的应用程序。
以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !