主要摘抄自《java高并发核心编程》
IO读写的基本原理
大多数情况下,Linux系统中用户程序的IO读写程序并没有进行物理设备级别的读写,而是在用户缓冲区和内核缓冲区之间直接进行数据的交换。外部设备的直接读写涉及操作系统的中断。发生系统中断时,需要保存之前的进程数据和状态等信息,结束中断之后,还需要恢复之前的进程数据和状态等信息。为了减少底层系统的频繁中断所导致的时间损耗、性能损耗,出现了内核缓冲区。
阻塞与非阻塞 同步与异步
阻塞IO(Blocking IO)指的是需要内核IO操作彻底完成后才返回到用户空间执行用户程序的操作指令。
非阻塞IO(Non-Blocking IO,NIO)指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间去执行后续的指令
同步IO是指用户空间(进程或者线程)是主动发起IO请求的一方,系统内核是被动接收方。
异步IO指系统内核是主动发起IO请求的一方,用户空间是被动接收方。
四种主要的IO模型
同步阻塞IO
从Java应用程序发起IO系统调用开始,直到内核IO操作彻底完成后才返回到用户空间执行用户程序的操作指令。
- 优点:应用程序开发非常简单;在阻塞等待数据期间,用户线程挂起,基本不会占用CPU资源。
- 缺点:一般情况下会为每个连接配备一个独立的线程,一个线程维护一个连接的IO操作。在高并发的应用场景下,阻塞IO模型需要大量的线程来维护大量的网络连接,内存、线程切换开销会非常巨大,性能很低,基本上是不可用的。
同步非阻塞IO
同步非阻塞IO指的是用户进程主动发起,不需要等待内核IO操作彻底完成就能立即返回用户空间的IO操作。
特点应用程序的线程需要不断地进行IO系统调用,轮询数据是否已经准备好,如果没有准备好就继续轮询,直到完成IO系统调用为止。
- 优点:每次发起的IO系统调用在内核等待数据过程中可以立即返回,用户线程不会阻塞,实时性较好。
- 缺点:不断地轮询内核,这将占用大量的CPU时间,效率低下。
IO多路复用
一个用户进程(或者线程)可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),用户空间便可以进行相应的IO系统调用,阻塞线程,将数据从内核缓冲区复制到用户缓冲区。
目前支持IO多路复用的系统调用有select、epoll等。几乎所有的操作系统都支持select系统调用,它具有良好的跨平台特性。
特点是:IO多路复用模型的IO涉及两种系统调用,一种是IO操作的系统调用,另一种是select/epoll就绪查询系统调用。
- 优点:一个选择器查询线程可以同时处理成千上万的网络连接,所以用户程序不必创建大量的线程,也不必维护这些线程,从而大大减少了系统的开销。
异步IO
在异步IO模型中,当用户线程收到通知时,数据已经被内核读取完毕并放在了用户缓冲区内,内核在IO完成后通知用户线程直接使用即可。
异步IO类似于Java中典型的回调模式,用户进程(或者线程)向内核空间注册了各种IO事件的回调函数,由内核去主动调用。