我看到这是一个旧问题,但我认为有些东西被忽略了,@nickdu试图指出但并不十分清楚。
在这个讨论中有四种与IO有关的类型:
阻塞IO
非阻塞IO
异步IO
异步非阻塞IO
混淆起源于我认为定义模糊,所以让我试着澄清一下。
首先,让我们谈谈IO。当我们有缓慢的IO时,这是最明显的,但IO操作可以是阻塞或非阻塞的。这与线程无关,而是与操作系统的接口有关。当我请求操作系统进行IO操作时,我可以选择等待所有数据准备就绪(阻塞),或获取现在可用的内容并继续进行(非阻塞)。默认情况下是阻塞IO。使用阻塞IO编写代码要容易得多,因为路径要清晰得多。但是,您的代码必须停止并等待IO完成。非阻塞IO需要在较低级别上与IO库进行接口,使用select和read / write而不是提供方便操作的更高级别库。非阻塞IO还意味着您需要在操作系统完成IO时有一些要处理的内容。这可能是多个IO操作或计算已完成的IO。
阻塞IO - 应用程序等待操作系统收集所有字节以完成操作或到达末尾。这是默认设置。对于非常技术性的人来说,初始化IO的系统调用将安装一个信号处理程序,等待处理器中断,当IO操作进展时会发生此中断。然后,系统调用将开始休眠,暂停当前进程的操作一段时间,或直到进程中断发生。
非阻塞式IO - 应用程序告诉操作系统它只需要现在可用的字节,然后继续执行,同时操作系统会并发地收集更多字节。代码使用select来确定哪些IO操作有可用字节。在这种情况下,系统调用将再次安装信号处理程序,但不是睡眠,而是将信号处理程序与文件句柄关联,并立即返回。进程将负责定期检查文件句柄是否已设置中断标志。通常使用select调用完成此操作。
现在,异步的概念开始引起混淆。异步的一般概念仅意味着进程在执行后台操作时继续进行,其实现机制并不具体。该术语是模棱两可的,因为非阻塞式IO和线程式阻塞式IO都可以被认为是异步的。两者都允许并发操作,但资源需求不同,代码也大不相同。因为你问了一个"什么是非阻塞式异步IO"的问题,所以我要使用更严格的异步定义,即执行IO的线程系统可能是非阻塞的,也可能是阻塞的。
一般定义
异步IO - 编程IO允许多个并发IO操作发生。IO操作同时进行,因此代码不会等待尚未准备好的数据。
更严格的定义
异步IO - 编程IO使用线程或多进程来允许并发执行IO操作。
现在,有了这些更清晰的定义,我们有以下四种IO范例。
阻塞IO - 标准单线程IO,在应用程序继续执行之前等待所有IO操作完成。易于编写,没有并发性,因此对于需要多个IO操作的应用程序来说速度慢。进程或线程将在等待IO中断时休眠。
异步IO - 线程式IO,应用程序使用执行线程以并发地执行阻塞IO操作。需要线程安全的代码,但通常比另一种选择更容易阅读和编写。获得多个线程的开销,但具有清晰的执行路径。可能需要使用同步方法和容器。
非阻塞IO - 单线程IO,在应用程序使用select来确定哪些IO操作准备就绪,从而允许执行其他代码或其他IO操作,同时让操作系统处理并发IO。进程在等待IO中断时不会休眠,而是负责检查文件句柄上的IO标记。由于需要使用select检查IO标记,代码更加复杂,但不需要编写线程安全的代码或同步方法和容器。低开销的执行却牺牲了代码的复杂性。执行路径复杂。
异步非阻塞IO - 一种混合IO方法,旨在通过使用线程降低复杂性,同时尽可能地使用非阻塞IO操作来保持可扩展性。这是最复杂的IO类型,需要同步方法和容器以及复杂的执行路径。这不是轻易考虑编写的IO类型,通常只在使用库来掩盖复杂性时使用,例如 Futures 和 Promises。