Linux/Unix五种I/O模型
内容来源,侵删。
- 游双-《Linux高性能服务器编程》
- 牛客网-Linux高并发服务器开发
阻塞-blocking
调用者调用了某个函数,然后等待这个函数返回,在这期间
什么都不做
,不停的去检查这个函数有没有返回
,应用程序必须等这个函数返回才能进行下一步的动作。
- 即,针对阻塞I/O执行的系统调用可能因为无法立即完成而被操作系统
挂起
,直到等待的时间发生为止,才可以继续执行下一步的操作。- 可能被阻塞的系统调用包括accept、send、recv、connect。
非阻塞-non blocking (NIO)
非阻塞I/O执行系统调用总是立即返回,不管事件是否已经发生
,若事件没有发生,则返回-1,此时可以根据errno区分这两种情况,对于accept、recv和send、事件未发生时,errno通常被设置成EAGAIN
。- 我们只有在事件已经发生的情况下操作非阻塞I/O,才能提高程序的效率。因此,
非阻塞I/O通常要和其它I/O通知机制一起使用
,比如I/O多路复用和SIGIO信号。
I/O复用-IO multiplexing
I/O多路复用是最常用的I/O通知机制
。- 它指的是:
应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序
。- 在单进程/线程的情况下,可以检测多个客户的事件是否发生。
- I/O复用函数本身也是阻塞的,它们能提高程序效率的原因在于它们
可以同时监听多个I/O事件
。- 单单使用I/O多路复用并不能处理高并发,而要处理高并发还是需要结合多进程/线程。
信号驱动-signal driven
为某一进程安装一个信号处理函数,进程运行,当I/O事件就绪,该进程收到SIGIO信号,然后开始处理I/O事件。
- 我们可以为目标文件描述符指定宿主进程,被指定的宿主进程将捕获到SIGIO信号,当目标问文件名描述符上有事件发生时,SIGIO信号的信号处理函数将被触发,我们可
在该信号处理函数中对目标文件描述符执行非阻塞I/O操作
。
- 内核在第一个阶段是
异步
,在第二个阶段是同步
;信号驱动I/O与非阻塞I/O的区别在于它提供了消息通知机制
,不需要用户进程不断的轮询检查,减少了系统调用的次数,提高了效率。
补充:
- 同步与异步:
同步是执行或调用一个方法时,每次都需要拿到对应的结果才会继续往后执行;异步与同步相反,它会在执行或调用一个方法后就继续往后执行,不会等待获取执行结果。二者的区别就是处理请求发出后,是否需要等待请求结果,再去继续执行其他操作。
——来源线程与同步异步
异步I/O-asynchronous
- 从理论上来讲,阻塞I/O、I/O复用和信号驱动I/O都是
同步I/O
模型,因为在这三种I/O模型中,I/O的读写操作,都是在I/O事件发生之后,由应用程序来完成的。
对异步I/O而言,用户可以
直接对I/O执行读写操作
,这些操作告诉内核用户读写缓冲区的位置,以及I/O操作完成之后内核通知应用程序的方式。(POSIX规范)
- 在Linux中,每次调用aio_read函数告诉内核描数字缓冲区指针和缓冲区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序。
- 异步I/O的读写操作总是立即返回,无论I/O是否阻塞,因为
真正的读写操作已由内核接管
。
对比:
- 同步I/O模型要求
用户代码自行执行I/O操作
(将数据从用户缓冲区拷贝到内核缓冲区,从内核缓冲区拷贝到用户缓冲区)。- 异步I/O则是由
内核来执行I/O操作
(即数据在用户缓冲区域内核缓冲区的移动是由内核在"后台"完成的)。可以这样理解:
- 同步I/O向应用程序通知的是I/O
就绪事件
。- 异步I/O向应用程序通知的是I/O
完成事件
。