Python 的五种io模型理解
一 IO操作本质
数据复制的过程中不会消耗CPU
|
|
二 IO模型
1. BIO – 阻塞模式I/O
用户进程从发起请求,到最终拿到数据前,一直挂起等待; 数据会由用户进程完成拷贝
|
|
2. NIO – 非阻塞模式I/O
用户进程发起请求,如果数据没有准备好,那么立刻告知用户进程未准备好;此时用户进程可选择继续发起请求、或者先去做其他事情,稍后再回来继续发请求,直到被告知数据准备完毕,可以开始接收为止; 数据会由用户进程完成拷贝
|
|
3. IO Multiplexing - I/O多路复用模型
类似BIO,只不过找了一个代理,来挂起等待,并能同时监听多个请求; 数据会由用户进程完成拷贝
|
|
4. AIO – 异步I/O模型
发起请求立刻得到回复,不用挂起等待; 数据会由内核进程主动完成拷贝
|
|
5 select poll 和epoll
|
|
三 同步I/O与异步I/O
- 同步I/O
- 概念:导致请求进程阻塞的I/O操作,直到I/O操作任务完成
- 类型:BIO、NIO、IO Multiplexing
- 异步I/O
- 概念:不导致进程阻塞的I/O操作
- 类型:AIO
注意:
- 同步I/O与异步I/O判断依据是,是否会导致用户进程阻塞
- BIO中socket直接阻塞等待(用户进程主动等待,并在拷贝时也等待)
- NIO中将数据从内核空间拷贝到用户空间时阻塞(用户进程主动询问,并在拷贝时等待)
- IO Multiplexing中select等函数为阻塞、拷贝数据时也阻塞(用户进程主动等待,并在拷贝时也等待)
- AIO中从始至终用户进程都没有阻塞(用户进程是被动的)
四 并发-并行-同步-异步-阻塞-非阻塞
|
|
五 IO设计模式
|
|
Reactor模式通常采用IO多路复用机制进行具体实现
|
|
Proactor模式通常采用OS Asynchronous IO(AIO)的异步机制进行实现
|
|
Reactor模式和Proactor模式都是事件驱动,主要实现步骤:
- 事件注册:将事件与事件处理器进行分离。将事件注册到事件循环中,将事件处理器单独管理起来,记录其与事件的对应关系。
- 事件监听:启动事件循环,一旦事件已经就绪/完成,就立刻通知事件处理器
- 事件分发:当收到事件就绪/完成的信号,便立刻激活与之对应的事件处理器
- 事件处理:在进程/线程/协程中执行事件处理器
使用过程中,用户通常只负责定义事件和事件处理器并将其注册以及一开始的事件循环的启动,这个过程就会是以异步的形式执行任务。
Reactor模式
Proactor模式
对比分析
Reactor模型处理耗时长的操作会造成事件分发的阻塞,影响到后续事件的处理;
Proactor模型实现逻辑复杂;依赖操作系统对异步的支持,目前实现了纯异步操作的操作系统少,实现优秀的如windows IOCP,但由于其windows系统用于服务器的局限性,目前应用范围较小;而Unix/Linux系统对纯异步的支持有限,因而应用事件驱动的主流还是基于select/epoll等实现的reactor模式
Python中:如asyncio、gevent、tornado、twisted等异步模块都是依据事件驱动模型设计,更多的都是使用reactor模型,其中部分也支持proactor模式,当然需要根据当前运行的操作系统环境来进行手动配置
每天逼着自己写点东西,终有一天会为自己的变化感动的。这是一个潜移默化的过程,每天坚持编编故事,自己不知不觉就会拥有故事人物的特质的。 Explicit is better than implicit.(清楚优于含糊)