I/O 是 Input / Output 的缩写

不管是 Java 还是 Python,在程序运行时,总是会遇到 IO 的问题,IO 包括了对操作系统的的读写,对网络的读写等。

一般来讲,涉及到 IO ,尤其是需要通过请求响应的方式读写网络数据时,总会遇到阻塞的问题。有阻塞,就必然会影响程序的效率。

所以我们根据不同的 IO 方式,提出了这三种比较常见的 I/O 模式

什么是 BIO,NIO,AIO

BIO,全称 Blocking I/O,即同步阻塞  I/O 模式,数据的读写必须阻塞在一个线程内等待完成。

NIO,全称 Non-Blocking I/O,即同步非阻塞 I/O 模式,数据的读写可以放在后台中运行(这个后台可以是一个线程,也可以是一个进程),但是必须有额外的「监控」线程去监控后台 I/O 的状态,一旦完成,由监控线程通知主线程。

AIO,全称 Asynchronous I/O 即异步 IO 模式,数据的读写基于事件和回调机制,主线程在后台(这个后台可是一个线程,也可以是一个进程)注册一个 I/O 事件,并提供一个回调接口,之后就不需要关心后台运行的情况,也不需要额外给一个监控线程监控后台状态。当后台完成相关 I/O 操作后,自行调用主线程的回调函数,「通知」主线程已完成。

下面根据三个不同的 IO 情况,通过对操作系统内的文件拷贝的场景,各举一个例子,只是大概说明一下三种模式的不同特性,有些细节画的不对的地方,欢迎提出来讨论。

Blocking I/O

ex-bio

如果是 BIO 的模式下,我们请求拷贝文件,主线程调用拷贝进程之后,必须等待拷贝进程完成拷贝操作,才能执行接下来的动作。

Non-Blocking I/O

ex-nio

如果是 NIO 的模式下,当我们请求拷贝文件后,主线程不必等着拷贝进程完成拷贝,可以执行接下来的操作,但是需要在主线程外,另外开一个线程,去不时的查看文件拷贝的状态,看是否成功或失败。当文件拷贝进程处理完毕后,由这个子线程去告诉主线程已经完成,主线程得到通知后,执行完成之后的逻辑。

Asynchronous I/O

aio

当在 AIO 模式下,我们需要拷贝文件后,主线程只需要”注册“一个拷贝事件,并提供一个回调函数接口,主线程就可以执行接下来的操作,并且不用另外开线程去关心拷贝的状态或进度。当拷贝的进程处理完毕之后,只需要调用主线程的回调函数接口,”通知“主线程,已经处理完毕。

总结

三种模式,可以说是 I/O 处理的迭代过程,我觉得并没有哪种场景适合哪种模式的说法,异步的方式,是三者中最高效,占用资源也最少的模式,所以任何生产环境下,都应是首选的模式。唯一的缺点,就是写异步代码,门槛比较高,写起来麻烦,维护可读性也相对差一点。