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