IO模型
一、IO的底层原理
对于计算机系统来说存在用户态
和内核态
,用户的程序进程通常运行在用户态,当需要进行IO操作时(读写文件、网络传输等),
只有内核空间才能进行系统态级别的资源有关操作(文件管理、进程通信、内存管理等),所以需要系统调用
委托操作系统代替执行,对于IO读写,一般会使用read&write两大系统调用。
二、内核缓存与进程缓冲区
缓冲区的目的是为了减少频繁的系统调用。有了缓冲区,操作系统使用read函数把数据从内核缓冲区复制到进程缓冲区,write把数据从进程缓冲区复制到内核缓冲区中。等待缓冲区达到一定数量的时候,再进行IO的调用,提升性能。对于用户程序,大多情况下,并没有实际的IO操作,而是在对写自己的进程缓冲区。
三、常见的IO模型
1.同步阻塞IO(Blocking IO)
同步阻塞 IO 模型中,应用程序发起 read 调用后,会一直阻塞,直到内核把数据拷贝到用户空间。
这种IO模型的最大特点就是,一个客户端连接对应一个进程。
在客户端连接数量不高的情况下,是没问题的。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
2、同步非阻塞IO
非阻塞IO,指的是用户程序不需要等待内核IO操作完成后,用户程序只需定期访问数据(系统调用)是否准备完成,内核立即返回给用户一个状态值,用户进程继续执行自己的操作,处于非阻塞的状态。
优点:不需要一直阻塞等待内核空间准备数据,用户线程可以做自己的事情。
缺点:需要不断的重复发起IO系统调用,这种不断的轮询,将会不断地询问内核,这将占用大量的 CPU 时间,系统资源利用率较低。
3、IO多路复用
IO 多路复用模型中,用户线程首先发起 select 调用,询问内核数据是否准备就绪,等内核把数据准备好了通知用户程序,用户线程再发起 read 调用。但是,read 调用的过程(数据从内核空间 -> 用户空间)还是阻塞的。
优缺点:
优点:
- 用select/epoll的优势在于,它可以同时处理成千上万个连接(connection)。与一条线程维护一个连接相比,I/O多路复用技术的最大优势是:系统不必创建线程,也不必维护这些线程,从而大大减小了系统的开销。
- Java的NIO(new IO)技术,使用的就是IO多路复用模型。在linux系统上,使用的是epoll系统调用。
缺点:
本质上,无论是select还是epoll系统调用,属于同步IO,也是阻塞IO。都需要在读写事件就绪后,自己负责进行读写,而这个读写过程是阻塞的。
4、异步IO模型(AIO)
流程:用户线程通过系统调用,告知内核执行某个IO操作,用户线程返回,内核在整个IO操作(数据准备、数据复制)完成后,通知用户线程,用户执行后续的业务操作。
与NIO不同的是,内核态不但负责数据的准备,也会执行数据的复制(内核空间->用户空间)
异步IO模型的特点:
在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的。用户线程需要接受的IO操作完成的事件,或者说注册IO操作完成的回调函数,到操作系统的内核。
缺点:
底层操作系统提供大量的支持,去做大量的工作。并且异步IO模型并不完善。