I/O模型包含5种
阻塞I/O、非阻塞I/O、I/O复用、事件(信号)驱动I/O、异步I/O
进程想要获取磁盘中的数据,需要发起系统调用,通知内核。因为只有内核才能和磁盘交互。
当进程发起系统调用的时候,系统调用进入内核模式,然后开始I/O操作:
磁盘将数据加载进内核的内存空间;
内核的内存空间的数据copy到用户的内存空间。
调用过程:
进程需要对磁盘中的数据进行操作,会向内核发起一个系统调用,然后改进程会被挂起或者进入睡眠状态,也叫不可中断的睡眠,只有当系统调用的结果完成后,进程会被唤醒。具体过程如下:
- 进程向内核发起一个系统调用
- 内核接收到系统调用,发现是一个我呢间的请求,通过磁盘把文件读取出来
- 磁盘接收到内核的命令后,把数据拷贝到内核的内存空间
- 内核的内存空间接收到数据后,把数据拷贝到用户进程的内存空间
- 进程的内存空间获取数据后,给内核发送通知
- 内核把接收到的通知回复给进程,这个过程为唤醒进程,然后进程拿到数据,进行后续处理
阻塞:是指系统调用返回结果前,用户进程被挂起,直到系统调用返回结果。
非阻塞:进程发起I/O调用,I/O需要一点时间来完成,进程先去进行其他的操作。没隔一段时间,询问内核数据是否准备结束,结束则进程获取到数据,继续执行,此过程也叫作盲等待。
I/O多路复用select
使用多路复用的原因:某个进程阻塞在多个I/O上,一个进程既要等待从键盘输入信息,又要准备从磁盘装入信息,调用了两个I/O操作,其中一个I/O执行结束,另一个还在阻塞,,导致整个县城依旧处于睡眠状态,此时需要I/O多路复用来解决。
进程在调用I/O的时候,不是直接使用I/O的功能,而是在系统内核中,新增一个系统调用,帮助进程监控多个I/O,一旦一个进程需要系统调用的时候,向内核发起一个特殊的系统调用,这个进程就会被阻塞在这个复用器的调用上面,这个进程此时可以进行后面的操作。帮助进程监控这些I/O的工具就叫做I/O复用器。
Linux中的I/O复用器
select:进程调用的时候,把请求发送给select,可以引发多个,但是最多支持1024个。
poll:没有限制,但是1024个后会导致性能下降。
事件驱动
进程发起调用,通过回调函数,内核会记住是哪个进程申请的,一旦一阶段(磁盘将数据装载到内核的内存中),就可以向这个进程发起通知,这样第一阶段是非阻塞的,第二阶段依旧是阻塞的。
两种机制:
水平触发机制:内核通知进程来读取数据,进程没有读取数据,内核会一次又一次的通知进程。
边缘触发机制:内核只通知进程一次来取数据,进程在超时时间内随时可以取数据,取数据的通知发给进程。(例如:nginx)
异步AIO
只有当数据完全拷贝到用户线程的时候,才向服务进程返回信息。
只有在文件中可以实现AIO,网络异步IO不可实现。