五种I/O模型
- 同步阻塞IO模型(BlockIng IO)
- 同步非阻塞IO模型(Non-blockIng IO )
- 多路复用IO模型(IO Multiplexing )
- 异步IO(Asynchronous IO)
- 信号驱动IO模型
首先,我们需要明确几个基础概念:
同步
:操作系统种的概念:是指必须在先行条件满足之后才能开始执行某一任务。在这里主要是指在触发了IO操作之后必须等待IO操作完成,才能执行接下来的任务。有同步阻塞和同步非阻塞之分。
异步
:是指可以和某一个任务同时进行,互不干扰。在这里主要是指出发了IO操作后可以同时执行其他的任务。
阻塞
:表示是否停滞在某一状态,无法进行其他操作。
非阻塞
:开始某一任务后,可以进行其他操作,但需要定时询问此任务是否完成,也称为轮询。
同步阻塞IO模型(BlockIng IO)
从图中可以看出,同步阻塞模型中,线程在进行了系统调用之后,由于数据还没有准备好,此后一直处于内核态,直到数据准备完成并且从内核的缓冲区中拷贝到用户态的数据区中,系统才从内核才切换成用户态,才能继续执行下面处理数据的操作。
显而易见,这样的方式,大量的时间都阻塞在了内核态中,等待数据的时间都被白白浪费掉了。大大降低了系统的吞吐量,影响系统的并发性。
同步非阻塞IO模型:(Non-blocking IO)
同步非阻塞IO模型和同步阻塞IO模型最大的区别在于在第一次进行了系统调用后,系统不会一直停留在内核态等待,而是立即切换为用户态,此后每隔一段时间就切换回内核态去查看数据是否准备完成,如果没有准备好则再次回到用户态执行其他操作,若事已经准备完成则进入数据拷贝阶段。
可以看到,此时在等待数据到来的过程中,系统的时间已经不是被完全浪费的了,而是通过不断询问的方式来查看是否可以进行下一步操作了。效率虽然得到了提升,但在用户态和内核态之间频繁切换的花销过大,显然还是不够尽如人意。
IO多路复用模型(IO Multiplexing)。
首先需要明确的是,IO多路复用模型的select、poll、epoll都是同步IO,也就是说调用了这些方法之后,都需要等待某一事情发生后,才能继续后面的拷贝操作!
那么区别到底在哪里呢主要是在于多个IO事件都可以注册在同一个复用器(select、epoll)上,然后调用该方法后,系统就开始监听所有注册进来的IO事件,一旦有一个或者多个IO事件的数据准备完成后,便会促使复用器告知之前已经设置好的某一进程(或自己),进来完成后续的操作(比如本文中的拷贝数据)。
IO多路复用模型的主要优势在于可以用一个线程去处理多个IO事件。
而select、poll、epoll实现的区别究竟在哪里呢?
- 当select复用器上注册的IO事件有一个或者多个满足了条件时,便会告知之前注册好的另一进程(或自己),但并没有告知具体是哪一个IO事件满足了条件,需要此线程自己去遍历注册的所有IO事件来寻找。
- poll与select类似,区别在于select对于注册的IO事件的数量有限制,而poll没有此限制,但注册的事件数量过多时,性能明显下降。
- epoll与前两者最大的区别在于,注册器会告诉相应的线程,究竟是哪个IO事件满足了条件,不需要再去遍历所有的IO事件。
信号驱动的IO事件
信号驱动的IO模型,当线程进行系统调用时发现IO事件的数据还没有准备好,则立即切换回用户态,等内核态中的数据准备好了之后,向用户线程发送一个信号,告知此时已经可以进行数据的拷贝了,用户线程再次执行系统调用,切换到内核态拷贝相应的数据,
异步IO模型 (Asynchronous IO)
异步模型不阻塞,等到对应的IO事件数据准备完成后,如果IO成功的话,会直接将IO的结果返回给进程。