BIO(Blocking I/O):
同步并阻塞,线程发起IO请求,不管内核是否准备好IO操作,从发起请求起,线程一直阻塞,直到操作完成。服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销。
NIO(New I/O):
NIO基于Reactor,当socket有流可读或可写入socket时,操作系统会相应的通知应用程序进行处理,应用再将流读取到缓冲区或写入操作系统。 也就是说,这个时候,已经不是一个连接就要对应一个处理线程了,而是有效的请求,对应一个线程,当连接没有数据时,是没有工作线程来处理的。NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器(select、poll、epoll)上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。
AIO(Asynchronous I/O):
与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
阻塞:当试图对该文件描述符进行读写时, 如果当时没有东西可读,或者暂时不可写, 程序就进入等待/挂起状态, 直到有东西可读或者可写为止(强迫症,必须这件事做完才能做其他事情,否则一直等待)
非阻塞: 如果没有东西可读, 或者不可写, 读写函数马上返回, 而不会等待/挂起(先取号,可以去做其他事情,叫号后,过来完成该事情)
同步I/O:(触发I/O操作后,进行真正的I/O操作时)导致请求进程阻塞,直到I/O操作完成(该说法为POSIX标准定义,个人感觉有一点点问题,这把同步和阻塞挂钩了);获取I/O完成的方式,同步需要时刻主动关心I/O是否完成。同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。
异步I/O:(触发I/O操作后,进行真正的I/O操作时)不导致请求进程阻塞(该说法为POSIX标准定义,个人感觉有一点点问题,这把异步和非阻塞挂钩了);异步无需主动关心I/O是否完成,在I/O完成后会收到通知。异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时我们可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。
如果按照POSIX的定义:
I/O操作分为两部分,发起I/O请求,和I/O数据读写。阻塞、非阻塞主要是针对线程发起I/O请求后,是否立即返回来定义的,立即返回称为非阻塞I/O,否则称为阻塞I/O。
同步、异步主要针对I/O数据读写来定义的,读写数据过程中不阻塞线程称为异步I/O,否则,称为同步I/O。
AIO 是帮助你从内核中将数据复制到用户空间中,并调用你传入的回调方法。
NIO 是需要程序自己从内核中将数据复制到用户空间中,并需要程序自己调用相应的处理逻辑。
个人的理解是同步/异步主要针对被调用者的返回机制,而阻塞/非阻塞主要针对调用者的状态,二者很容易混淆,可以不必过分纠结,只需要弄清BIO、NIO和AIO的原理和区别即可。