为了OS的安全性等的考虑,进程是无法直接操作I/O设备的,其必须通过系统调用请求内核来协助完成I/O动作,而内核会为每个I/O设备维护一个buffer,请求 I/O 的一般流程如下所示
同步/异步:消息返回给你,你是立刻得到还是通过接受通知或者多次查询的方式得到
阻塞/非阻塞:执行一个操作,你是等操作结束再返回还是马上返回
从上图可以看到在整个过程中,当用户进程进行系统调用时,内核就开始了I/O的第一个阶段,准备数据到缓冲区中,当数据都准备完成后,则将数据从内核缓冲区中拷贝到用户进程的内存中,这时用户进程才解除block的状态重新运行。所以,Blocking I/O的特点就是在I/O执行的两个阶段都被block了。
从上图可以看到在I/O执行的两个阶段中,用户进程只有在第二个阶段被阻塞了,而第一个阶段(数据准备阶段)没有阻塞,但是在第一个阶段中,用户进程需要盲等,不停的去轮询内核,看数据是否准备好了,因此该模型是比较消耗CPU的。
从上图可以看到在I/O复用模型中,I/O 执行的两个阶段都是用户进程都是阻塞的,但是两个阶段是独立的,在一次完整的I/O操作中,该用户进程是发起了两次系统调用。
和阻塞 I/O所不同的是这两个函数可以同时阻塞多个I/O操作。可以同时对多个读操作,多个写操作的I/O函数进行检测(),直到有数据可读或可写时,才真正调用I/O操作函数。
该模型也叫作基于事件驱动的I/O模型,可以看到该模型中,只有在I/O执行的第二阶段阻塞了用户进程,而在是没有阻塞的。
乍看起来感觉和非阻塞模型很相似,其实不同之处就在于,该模型在I/O执行玩数据准备之后,会主动的通知用户进程数据已经准备完成,即对用户进程做一个回调。
epoll 为什么比 select 高级:
在该模型中,当用户进程发起系统调用后,立刻就可以开始去做其它的事情,然后直到I/O执行的两个阶段都完成之后,内核会给用户进程发送通知,告诉用户进程操作已经完成了。
Nginx 处理请求的 work 进程可以并行处理数千个的并发连接及请求就有一个原因是因为:
大量采用了多路复用及事件通知机制,工作进程在调用 IO 后,就去处理其他的请求,当 IO 调用返回后,会通知该工作进程
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。