I/O类型与模型

I/O类型:
        同步和异步
        阻塞和非阻塞
 
一次read操作两个阶段:用户空间的进程没有权限访问磁盘的,进程发起IO调用
(1)等待数据准备好:内核从磁盘中的数据加载至内核内存
(2)真正IO的阶段:内核内存数据在复制到进程内存(这个是真正执行IO的阶段)
 
        所以进程需要等待内核到内核内存和内核内存到进程内存的时间
 
1.同步和异步:synchronous,asyncronnous
关注的是被调用者的消息通知机制,被调用者如何通知调用者,调用者向被调用者进行系统调用函数
 
同步:调用发出之后不会立即返回,进程会一直询问内核准备好数据没有,但一旦返回,则内核返回最终结果,数据已经从内核内存复制到进程内存了(进程自己去询问内核,直到两阶段都复制完通知进程)没有通知机制
异步:调用发出之后,被调用方立即返回消息,但返回的并非最终结果;被调用者通过状态、通知机制来通知调用者,或通过回调函数来处理(内核自己都把数据复制完了通知进程数据已经复制完)有通知机制
 
 
2.阻塞和非阻塞:block,nonblock
关注的是调用者等待被调用者返回调用结果时的状态
 
阻塞:调用结果返回之前,调用者会被挂起,叫不可中断睡眠,调用者只有在得到返回结果时候才能继续。(两阶段都阻塞)
非阻塞:调用者在结果返回之前不会被挂起,即调用不会阻塞当前进程(第一阶段不阻塞,第二阶段依然阻塞)
 
**************************************************************************************************************************************************************
 
同步是进程调用内核,内核从磁盘读取数据存入内核内存这段时间,进程会一直询问内核准备好数据没有,直到全部读进内存准备好了,然后告诉进程来内核内存来复制数据。
 
异步是进程调用内核,内核从磁盘读取数据存入内核内存这段时间进程是活动的,不需要等待内核准备好数据,当内核从磁盘数据全部读取,然后通知进程过来复制数据到进程内存,或者通过回调函数来处理。
 
阻塞是进程调用内核,内核从磁盘读取数据的这段时间,进程是被挂起的或者叫不可中断睡眠处于等待状态,只有内核告诉进程准备好之后,才会继续够继续工作(比如从内核内存复制数据)
 
非阻塞是进程调用内核,内核从磁盘读取数据的这段时间,进程不会被挂起
 
 
I/O模型:
blocking IO: 阻塞IO
nonbocking IO:非阻塞IO
IO multiplexing:IO复用
select()BSD
                poll()SysV
signal driven IO:事件驱动IO
                epoll(linux上的边缘触发)、kqueue
水平触发:多次通知,浪费资源
边缘触发:只通知一次
aysnchronous IO:异步IO
 
一个进程在某种情况下只能处理单步IO,而prefork要处理网络IO和磁盘IO,所以prefork不是阻塞IO
 
I/O动作如何执行?
 
 
 
一、阻塞I/O
同步阻塞IO是进程调用内核,内核从磁盘读取数据至内核内存的时候,进程处理等待状态,准备好数据,进程就复活复制数据,第二阶段进程复制数据,进程依然在等待,所以第一第二阶段依然是阻塞的,是同步的IO
 
二、非阻塞I/O
非阻塞是内核不通知进程,进程会几秒钟询问内核数据准备好了没,时间都花在询问的过程了,叫盲等待,第一段非阻塞,但第二阶段依然是阻塞状态,从内核内存复制到进程内存,进程依然是等待状态处于阻塞状态,所以比起阻塞依然没有太大优势,是同步的IO
 
三、I/O复用
IO复用指的是任何一个进程,在某种情况下进程自身只能处理一个IO,但是web是要处理两路IO的,一个是网络IO,另外一个磁盘IO,内核中开发了多路IO或IO复用,进程需要调用IO的时候,都把IO请求交给内核中的select()函数或者poll()函数,最大不能超过1024个,如果超过1024个性能会减少,函数能够处理两个IO,处理网络和磁盘IO,所以prefork就是基于IO复用只能处理1024个请求,第一阶段是非阻塞,进程等待在select()函数的处理上,但是select()是可以接受其他进程的请求的,第二阶段阻塞在进程复制内核内存中的数据了。而worker模式也是IO复用,带有通知机制的是异步的
 
 
 
四、事件驱动I/O
事件驱动IO,是指进程调用内核,内核从磁盘中加载数据到内核内存,进程是活动的,进程可以接受其他请求,所以是多线程响应多个请求的过程,内核准备好数据会通知进程过来复制数据,第一阶段是非阻塞的,第二阶段依然要进程过来复制内核内存中的数据,所以还是阻塞的。带有通知机制的是异步的,所以事件驱动I/O是异步的;event模式是用事件驱动IO,基于事件驱动机制来维持多个用户请求,省掉了大量的上下文切换时间
 
五、异步I/O
异步IO是进程接受多个请求,进程调用内核,内核完成从磁盘读取数据,和把内核内存的数据复制到进程内存,都由内核完成了第一第二阶段,是真正的非阻塞,带有通知机制的是异步的
 
 
C10K问题,1万个并发连接  
 
5种I/O模型的比较:
 
阻塞I/O、非阻塞I/O、I/O复用都是同步
事件驱动I/O、异步是异步的
 
 
select/poll/epoll
 
select:本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理
缺点:1.单个进程可见识的fd数量被限制,即能监听端口的大小有限
                cat /proc/sys/fs/file-max
           2.对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低
           3.需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大
 
 
poll:本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态;其没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有一个缺点:
        1. 大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意
        2. poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd
 
epoll:支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次;使用"事件"的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知
 
优点:
        1.没有最大并发连接的限制,能打开的fd的上限远大于1024(1G的内存上能监听越10万个端口)
        2.效率提升:非轮询的方式,不会随着fd数目的增加而效率下降;只有活跃可用的fd才会调用callback函数,即epoll最大的优点就在于它只管理"活跃"的连接,而跟连接总数无关
        3. 内存拷贝,一用nmap() 文件映射内存加速与内核空间的消息传递;即epoll使用nmap减少复制开销
 
 
 
 
 
posted @ 2016-08-22 11:55  Python自动化运维之路  阅读(357)  评论(0编辑  收藏  举报