IO 模型
内核空间与用户空间
操作系统的核心是内核,可以系统受访问受保护的内存,也有访问底层物理设备的权限,为了保护内核安全,避免用户进程直接操作系统内核,操作系统将虚拟内存分为内核空间和用户空间;
用户空间不能直接访问内核空间,也不能调用内核函数,需要发起系统调用,从用户态切换到内核态;
同步与异步, 阻塞与非阻塞
阻塞与非阻塞主要是从调用者等待返回结果等角度看;
同步与异步是从被调用者处理请求的方式看问题,比如先返回,后台再处理,处理完成再回调通知给调用者结果,这就是异步;
一台机器应用 A 到另一台 B 机器应用 B,数据是怎么传输的?
(1) A 数据从进程用户空间到操作系统内核
(2) 数据从内核空间 DMA 拷到网卡
(3) 网卡通过网线将数据发到交换机等物理设备,最后到 B 机器的网卡
(4) B 机器从网卡将数据 DMA 拷贝到操作系统内核
(5) 数据从内核到进程用户空间
IO 模型
举个例子,读数据分为两步:
(1) 数据准备(等待数据到达)
(2) 将准备好的数据,拷贝到内核空间,再从内核空间拷贝到用户进程空间
1. 阻塞式 I/O
Blocking I/O;
发起 recvfrom 系统调用,在返回数据前,一直阻塞
2. 非阻塞式 I/O
Non-Blocking I/O;
配置 socket 为 Non-Blocking 模式后,发起 recvfrom 系统调用,就绪,在数据未就绪前,会返回 EWOULDBLOCKING;
这种模式大量消耗 CPU
3. IO Multiplexing
NIO, IO 多路复用, 事件驱动; 需要 select、poll、epoll(linux)来配合;
将数据准备和数据拷贝两个过程分离,select 负责弹出数据准备好的 socket,recvfrom 负责数据拷贝;
多个 socket 注册到一个 selector 上,主线程循环调用 selector.select 方法,如果没有任何 socket 有事件就绪,则阻塞;有就绪事件,就处理就绪事件;
优点是一个线程可以监听多个 socket 的事件,并且只有在存在就绪事件时,才会使用 IO 资源
4. Signal-Driven I/O
信号驱动 I/O;
用户线程发起一个 IO 请求,会给对应 socket 注册一个信号函数,用户线程继续执行,内核有准备就绪的数据时,会通知回调函数,然后发起 recvfrom 系统调用,拷贝数据到用户空间,用户执行读写事件处理;
5. AIO
异步 I/O;
发起 aio_read 系统调用,通知内核,直接返回,内核会异步处理数据(包括等待数据准备好,将数据拷贝到用户空间);
优点是全程异步,操作全部托管内核处理;
缺点是无法一次读取更多准备好的数据;
评论