深入聊聊Linux 五种IO模型( 三 )


1、服务器需要同时处理多个处于监听状态或者多个连接状态的套接字 。
2、服务器需要同时处理多种网络协议的套接字 。
此时你是不是想到的了redis如何做的啊,redis用的就是多路复用 。
 
3、信号驱动IO 

深入聊聊Linux 五种IO模型

文章插图
 
简介:两次调用,两次返回;
首先我们允许套接口进行信号驱动 I/O,并安装一个信号处理函数,进程继续运行并不阻塞 。当数据准备好时,进程会收到一个 SIGIO 信号,可以在信号处理函数中调用 I/O 操作函数处理数据 。
4、异步IO模型 
相对于同步IO,异步IO不是顺序执行 。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情 。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知 。IO两个阶段,进程都是非阻塞的 。
Linux提供了AIO库函数实现异步,但是用的很少 。目前有很多开源的异步IO库,例如libevent、libev、libuv 。
 
深入聊聊Linux 五种IO模型

文章插图
 
 
5、5种I/O模型的比较 
不同 I/O 模型的区别,其实主要在等待数据和数据复制这两个时间段不同,图形中已经表示得很清楚了 。
通过上面的图片,可以发现non-blocking IO和asynchronous IO的区别还是很明显的 。在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存 。而asynchronous IO则完全不同 。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知 。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据 。
 
深入聊聊Linux 五种IO模型

文章插图
 
 
同步非阻塞方式相比同步阻塞方式:
优点:能够在等待任务完成的时间里干其他活了(包括提交其他任务,也就是 “后台” 可以有多个任务在同时执行) 。
缺点:任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作,而任务可能在两次轮询之间的任意时间完成 。这会导致整体数据吞吐量的降低 。
三、select 、poll 、epoll的区别?1、支持一个进程所能打开的最大连接数
 
深入聊聊Linux 五种IO模型

文章插图
 
2、FD (文件描述符)剧增后带来的 IO 效率问题
 
深入聊聊Linux 五种IO模型

文章插图
 
3、消息传递方式
 
深入聊聊Linux 五种IO模型

文章插图
 
综上,在选择 select,poll,epoll 时要根据具体的使用场合以及这三种方式的自身特点 。
1、表面上看 epoll 的性能最好,但是在连接数少并且连接都十分活跃的情况下,select 和 poll 的性能可能比 epoll 好,毕竟 epoll 的通知机制需要很多函数回调 。
2、select 低效是因为每次它都需要轮询 。但低效也是相对的,视情况而定,也可通过良好的设计改善
 
补充知识点:
Level_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写 。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!
Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写 。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!
select(),poll()模型都是水平触发模式,信号驱动 IO 是边缘触发模式,epoll()模型即支持水平触发,也支持边缘触发,默认是水平触发 。


推荐阅读