(技术点)谈谈那些I/O方式----BIO、NIO、AIO

一、事件分离器

要使用IO,就要说到事件分离器。在IO读写时,将IO请求与读写操作分离调配进行,需要用到事件分离器。

事件分离器对象可以将来自事件源的IO时间分离出来,并分发到对应的read、write时间处理器(Event Handler),需要开发人员预先注册需要处理的时间以及事件处理器(回调函数)。

事件分离器分为两种:

  • Reactor事件分离器
  • preactor事件分离器

Reactor模式采用同步IO,而Proactor采用异步IO。

同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知(异步的特点就是通知)。

阻塞和非阻塞是针对于进程访问数据的时候,根据IO的就绪状态采用不同的方式,说白了就是读取或者写入操作函数的实现方式不同。阻塞方式下,读取或者写入函数会一直等待,而在非阻塞方式下,读取或写入操作会立即返回一个状态值。

下面对比一下同步和阻塞四种状态下的运行方式:

同步阻塞:用户进程发起一个IO操作后,必须等待IO操作完成,只有真正完成了IO操作后,用户进程才能继续进行,否则会一直阻塞等待IO完成。

同步非阻塞:用户进程发起一个IO操作以后,可以先去做 其他事情,但是用户进程需要时不时的去询问IO是否就绪。这样虽然不会阻塞用户进程,但是经常询问IO状态,导致了不必要的CPU资源浪费。

异步阻塞:应用程序发起一个IO操作后,不等待内核IO操作的完成,等内核IO操作完成之后会通知应用程序。(同步必须应用程序主动起询问,而异步会等待内核通知应用程序)。由于此时的通知是通过 select系统调用完成的,而select函数本身的实现方式是就是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄(就绪的没有就绪的都有监听,epoll是select的替代方式,只监听就绪的文件句柄),从而提高系统的并发性!

异步非阻塞:在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。

Reactor事件分离器和preactor事件分离器的区别

reactor:

  • 应用程序注册读/写就绪事件和相关联的事件处理器
  • 事件分离器等待事件的发生 (Reactor负责)
  • 当发生读就绪事件的时候,事件分离器调用第一步注册的事件处理器(Reactor负责)
  • 事件处理器首先执行实际的读取操作,然后根据读取到的内容进行进一步的处理(用户处理器负责)

proactor:

 

  • 应用程序初始化一个异步读取操作,然后注册相应的事件处理器,此时事件处理器不关注读取就绪事件,而是关注读取完成事件,这是区别于Reactor的关键。
  • 事件分离器等待读取操作完成事件
  • 在事件分离器等待读取操作完成的时候,操作系统调用内核线程完成读取操作(异步IO都是操作系统负责将数据读写到应用传递进来的缓冲区供应用程序操作,操作系统扮演了重要角色),并将读取的内容放入用户传递过来的缓存区中。这也是区别于Reactor的一点,Proactor中,应用程序需要传递缓存区。
  • 事件分离器捕获到读取完成事件后,激活应用程序注册的事件处理器,事件处理器直接从缓存区读取数据,而不需要进行实际的读取操作。

与reactor相比,proactor显然系统调用更少。

从上面可以看出,Reactor和Proactor模式的主要区别就是真正的读取和写入操作是有谁来完成的,Reactor中需要应用程序自己读取或者写入数据,而Proactor模式中,应用程序不需要进行实际的读写过程,它只需要从缓存区读取或者写入即可,操作系统会读取缓存区或者写入缓存区到真正的IO设备.

 综上所述,同步和异步是相对于应用和内核的交互方式而言的,同步需要主动去询问,而异步的时候内核在IO事件发生的时候通知应用程序,而阻塞和非阻塞仅仅是系统在调用系统调用的时候函数的实现方式而已。

二、同步阻塞IO(BIO)

这是最基本简单的IO方式,其根本特征是做完一件事再去做另一件事,一件事一定要等前一件事做完了。符合传统的顺序开发思想,所以BIO开发比较简单,易于把握。

我们熟知的Socket编程就是BIO,一个socket连接一个处理线程(这个线程负责这个Socket连接的一系列数据传输操作)。阻塞的原因在于:操作系统允许的线程数量是有限的,多个socket申请与服务端建立连接时,服务端不能提供相应数量的处理线程,没有分配到处理线程的连接就会阻塞等待或被拒绝。(一个连接一个线程)

三、同步非阻塞IO(NIO)

New IO是对BIO的改进,基于Reactor模型。

一个socket连接只有在特定的时候才会发生数据IO操作,但是绝大多数情况,这个“数据通道”是空闲的,但是却占用着线程资源。NIO对他做出的改进是:一个请求占用一个线程,请求完成了,线程释放。在链接到服务端的众多的socket中,只有需要IO时,才会获取服务端线程,这样不会因为线程不够用而限制了socket的接入。

 

 

 

 

 

 

你可能感兴趣的:(技术点)