四种IO模型
同步非阻塞IO模型
两个任务是由同一个线程执行,IO调用逻辑与IO执行逻辑由同一个线程完成,他们的执行是串行的,即同步。此时该线程一直在做while(true)查看user buffer中的数据是否就绪:若就绪,则执行IO调用后的语句。若没有就绪,则继续while(true)。整个过程线程一直处于运行状态,没有发生阻塞。
同步阻塞IO模型
两个任务是由同一个线程执行,IO调用逻辑与IO执行逻辑由同一个线程完成,他们的执行是串行的,即同步。此时该线程首先向user buffer注册监听,监听其数据是否就绪,然后阻塞自己。若数据就绪,则唤醒阻塞的线程,继续执行IO调用后的语句。
异步非阻塞IO模型
两个任务是由两个不同的线程完成。在IO执行线程执行期间,IO调用后语句也在同时执行。只不过IO调用线程会为IO执行线程添加一个异步监听,监听IO操作是否结束,若结束,则再处理“IO调用后语句”与Future回调语句的优先级问题:是执行完毕IO调用语句在执行Future回调,还是先把IO调用后语句挂起,然后马上执行Future回调,回调执行完毕后,再继续执行IO调用后语句。
异步阻塞IO模型
两个任务是由两个不同的线程完成。在IO调用线程调用了IO执行线程后,其首先向这个IO执行线程的Future添加一个监听。监听其IO是否执行完毕,然后阻塞自己。若执行完毕,则唤醒阻塞的IO调用线程。
Reactor模型的IO
- 其IO为同步非阻塞IO
- 以channel发起读操作请求为例来分析整个过程
- 当channel的执行过程发起了read()调用后,其会向selector注册OPT_READ事件,然后该线程会不停的查看该事件是否就绪,此就绪是由selector通知的
- 当selector接收到这个注册后,其就会不停的查看该channel所关联的网卡缓存是否有了数据。当selector轮询到该channel的网卡缓存中具有了数据后,该读操作就绪
- 此时该线程就查看到了就绪,会发起system.call,将网卡缓冲中的数据读取到user buffer中。这些操作完成后,会再执行read()后面的逻辑。整个执行过程,该线程未发生阻塞。所以Reactor模型是同步非阻塞模型的。
Proactor模型的IO
- 其IO为异步非阻塞IO
- 以channel发起读操作请求为例来分析整个过程
- 当channel的执行线程调用了异步的read()操作后,其会继续执行read()后的逻辑。而该read()会将本次操作注册到一个Proactor实例中,注册本次操作关注的事件为Read Complete。
- 一个channel的所有IO操作共享一个Proactor实例。或者说,一个Proactor实例处理同一channel中所有IO请求。这个Proactor实例是在channel创建时完成的初始化。每个Proactor实例具有一个绑定的过程,用于执行相关的IO操作。
- 当Proactro实例接受了read()操作注册后,其会为网络缓存注册一个监听。若网卡缓存中有了数据,则马上通过DMA控制将数据写入到user buffer中(和Reactor不同,是自动写入到用户缓存,而Reactor是由IO调用线程发起,因为IO调用线程和IO执行线程是同一个,所以也可以理解为IO执行线程。但是此处是直接由DMA写入到用户缓存中),则该IO操作完毕,产生Read Complete事件,此时会将事件写入到Proactor所维护的一个队列。Proactor实例会将队列中的事件发送给各个IO调用者线程,以使他们触发相应的回调。
- 当前read()操作的调用线程无需阻塞等待read()操作的完成,而是直接执行后面的逻辑。由于read()操作本身是由另外一个线程来执行,所以Proactor模型是“异步非阻塞IO”模型
- Reactor中的selector是一种事件分离器的实现。在Proactor中不存在事件分离器,但存在一个Proactor实例。该实例会根据不同的IO操作,监听不同的内容。例如,本例为网卡缓存注册了监听。