网络通信中经常用到IO操作,IO操作主要有BIO,NIO以及AIO等几种模式,要弄清这几种IO模式,又需要弄懂阻塞/非阻塞,同步/异步概念。网上对这几种概念的解释各不相同,我在本文中记录下我自己的理解。
一次IO请求操作,主要有数据准备和数据拷贝两个阶段。
- 数据准备阶段是系统内核准备数据,并准备等待被处理,阻塞与否主要发生在这个阶段。
- 数据拷贝是把数据从系统内核复制到应用程序中的过程。
这是因为"用户内存"并不能使用“系统内存”中的数据,需要将数据从内核拷贝到应用的内存中。
BIO(Blocking IO)指的是同步阻塞IO操作。
NIO(Non-Blocking IO)指的是同步非阻塞IO操作。
AIO(Asynchronous I/O)指的是异步非阻塞IO操作。
首先要弄清同步/异步以及阻塞/非阻塞是两个层次上的概念
同步/异步指的是消息通信机制,一种全局的概念。
- 同步:应用程序进行IO操作时,会等待结果的出现再返回结果值。
-
异步:进行IO操作时,应用程序直接返回值(可能是-1),等内核将结果计算出来,再通知应用程序。
阻塞/非阻塞指的是进程在等待请求结果时的状态。
- 阻塞:阻塞指的是当准备数据时,进程会进行等待,不进行其他操作,直到IO数据准备就绪,此过程中进程就像被阻塞了一样。
-
非阻塞:非阻塞指的是内核准备数据时,用户函数会直接返回而不会等待,用户进程会去定时轮询系统数据是否准备好,在此期间进程可以继续其他操作。
明白了以上概念,再看几种通信模式:
一.BIO
在BIO通信模式下,服务端每收到一个连接(socket),就会创建专门的线程(serversocket)响应该连接,这个连接会一直存在等待读取发来的数据,这个过程会阻塞所在线程,不能做别的事,直到操作结束返回结果值,因此这是同步阻塞。
BIO模式下,服务端连接多个客户端时,会开启多个线程响应连接。
二.NIO
NIO则不会对每个连接都开启单独线程,NIO主要由Buffer,Channel和Selector三部分组成。
- Buffer是缓存区,用户存放数据,方便复用。
- Channel是连接数据和缓存区的通道,数据通过通道写入缓存区或者通过通道读出来。相比常规流,通道有双向的并且可以异步读写,在NIO中,Buffer必须和Channel相结合使用。
- Selector是选择器,上面的Channel需要注册到Selector上,这样选择器就能同事维护多个Channel,当某个Channel的IO请求就绪时,Selector会为其开启一个操作线程,用select的优势在于它可以同时处理多个连接。
相比于BIO,NIO不需要为每个连接开启一个线程,而是统一由Selector管理,当连接没有IO操作时,不需要阻塞线程等待数据,只有当Selector检测到哪个Channel有有效的IO请求时,再为其开启操作线程,节省线程的开销,操作结束后返回结果值,故为同步非阻塞。
三.AIO
AIO则是特殊的API,与BIO和NIO不同,当应用程序访问内核请求数据后,会直接返回,此时操作系统会完成第一第二阶段,当数据准备完毕后再通知应用程序,此过程应用程序可做任意事情,在这一阶段,和NIO不同的是NIO会主动轮询操作系统数据是否准备完毕,而AIO则是等待系统主动通知,再去取数据。这个过程中AIO仅仅向内核发送了请求,直接返回了函数,所谓异步,整个过程由系统完成数据装配,更没有线程阻塞了。