一.概述
1.1文件描述符
Linux的内核将所有外部设备都看做一个文件来操作,对一个文件的读写操作会调用内核提供的系统命令,返回一个fd即文件描述符。
1.2 系统调用、用户空间、内核空间
为了保证操作系统的安全,将内存划分为内核空间和用户空间。内核空间的进程,可以访问硬件执行IO等操作,用户空间的进程只能通过系统调用来访问IO等系统资源。
1.3 IO模型划分依据
以读操作为例,在Linux系统中一次读操作可以分为两步。一是数据被拷贝到内核的缓冲区中;二是从内核缓冲区拷贝到应用程序的地址空间。
所以,当一个read操作发生时,它会经历两个阶段
- 等待数据准备(等待数据到达内核)(Waiting for the data to be ready)
- 将数据从内核拷贝到进程中(Copying the data from the kernel to the process)
正因为这两个阶段的存在,才产生了以下5种IO模型:
- 阻塞IO
- 非阻塞IO
- IO多路复用
- 信号驱动IO
- 异步IO
二.5种IO模型
2.1阻塞IO
阻塞I/O是默认情况下采用的I/O模型。以套接字接口为例,一次读取数据的操作如下:在进程空间调用recvform系统调用,等待数据到达内核,等待数据从内核拷贝到用户空间。整个等待过程进程都是阻塞的。其过程如下图所示:
特点:在IO执行的两个阶段进程都会都阻塞
2.2 非阻塞I/O
执行非阻塞I/O系统调用时,如果内核中的数据还没有准备好,会直接返回,不会阻塞。通过进程不断查询,直到数据在内核中就绪,便开始拷贝到用户空间。拷贝的过程中,进程还是被阻塞了,所以非阻塞IO也是同步IO。
特点:需要进程不断地主动询问kernel数据是否准备好了
2.3 I/O多路复用模型
单个进程处理多个网络连接IO,使用select\poll\epoll三种系统调用,不断轮询所有的连接,如果有数据到达内核则通知进程,进行数据拷贝到用户内存。
当调用select时,进程会进入阻塞状态,直到有数据到达。
这个图看起来和阻塞IO区别不大,甚至还多使用了一个系统调用
但它的优势在于可以同时监控多个IO连接。
所以,如果连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web servet性能更好。多路IO复用的优势并不是对于单个连接能处理的更快,而在于能处理更多的连接。
特点:优势在于同时处理大量请求
2.4 信号驱动I/O模型
执行过程:开启套接口信号驱动I/O功能,调用sigaction执行一个信号处理函数(此调用是非阻塞的);当数据准备就绪时,就为该进程生成一个SIGIO信号,通过信号回调通知应用程序调用recvform来读取数据,并通知主循环函数处理数据。
2.5 异步I/O
发起read操作后进程立马返回,整个Io过程不会产生任何block。kernel会等等数据准备完成,然后将数据拷贝到用户内存。当这一切都完成后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
![异步IO模型](https://img-blog.csdnimg.cn/20190717152455148.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Z4emhn,size_16,color_FFFFFF,t_70
微信搜一搜【第四单元】关注我的个人公众号