同步阻塞IO在等待数据就绪上花去太多时间,而传统的同步非阻塞IO虽然不会阻塞进程,但是结合轮询来判断数据是否就绪仍然会耗费大量的CPU时间。

多路IO复用提供了对大量文件描述符进行就绪检查的高性能方案。

select

select诞生于4.2BSD,在几乎所有平台上都支持,其良好的跨平台支持是它的主要的也是为数不多的优点之一。

select的缺点(1)单个进程能够监视的文件描述符的数量存在最大限制(2)select需要复制大量的句柄数据结构,产生巨大的开销 (3)select返回的是含有整个句柄的列表,应用程序需要遍历整个列表才能发现哪些句柄发生了事件(4)select的触发方式是水平触发,应用程序如果没有完成对一个已经就绪的文件描述符进行IO操作,那么之后每次select调用还是会将这些文件描述符通知进程。相对应方式的是边缘触发。

poll

poll 诞生于UNIX System V Release 3,那时AT&T已经停止了UNIX的源代码授权,所以显然也不会直接使用BSD的select,所以AT&T自己实现了一个和select没有多大差别的poll。

poll和select是名字不同的孪生兄弟,除了没有监视文件数量的限制,select后面3条缺点同样适用于poll。

面对select和poll的缺陷,不同的OS做出了不同的解决方案,可谓百花齐放。不过他们至少完成了下面两点超越,一是内核长期维护一个事件关注列表,我们只需要修改这个列表,而不需要将句柄数据结构复制到内核中;二是直接返回事件列表,而不是所有句柄列表。

/dev/poll

Sun在Solaris中提出了新的实现方案,它使用了虚拟的/dev/poll设备,开发者可以将要监视的文件描述符加入这个设备,然后通过ioctl()来等待事件通知。

/dev/epoll

名为/dev/epoll的设备以补丁的方式出现在Linux2.4中,它提供了类似/dev/poll的功能,并且在一定程度上使用mmap提高了性能。

kqueue

FreeBSD实现了kqueue,可以支持水平触发和边缘触发,性能和下面要提到的epoll非常接近。

epoll

epoll诞生于Linux 2.6内核,被公认为是Linux2.6下性能最好的多路IO复用方法。

int epoll_create(int size) 
 
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 
 
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

  • epoll_create 创建 kernel 中的关注事件表,相当于创建 fd_set
  • epoll_ctl 修改这个表,相当于 FD_SET 等操作
  • epoll_wait等待 I/O事件发生,相当于 select/poll 函数

epoll支持水平触发和边缘触发,理论上来说边缘触发性能更高,但是使用更加复杂,因为任何意外的丢失事件都会造成请求处理错误。Nginx就使用了epoll的边缘触发模型。

这里提一下水平触发和边缘触发就绪通知的区别,这两个词来源于计算机硬件设计。它们的区别是只要句柄满足某种状态,水平触发就会发出通知;而只有当句柄状态改变时,边缘触发才会发出通知。例如一个socket经过长时间等待后接收到一段100k的数据,两种触发方式都会向程序发出就绪通知。假设程序从这个socket中读取了50k数据,并再次调用监听函数,水平触发依然会发出就绪通知,而边缘触发会因为socket“有数据可读”这个状态没有发生变化而不发出通知且陷入长时间的等待。

因此在使用边缘触发的 api 时,要注意每次都要读到 socket返回 EWOULDBLOCK为止

=================================================================================

http://bbs.linuxpk.com/thread-43628-1-1.html

我们先来介绍下nginx  nginx :
支持高并发连接.官方测试的是5w并发连接但在实际生产中可制成2-4w并发连接数,得益于nginx使用最新的epoll(linux 2.6内核)和kqueue(freebsd)网络I/O模型.而apache使用的则是传统的select模型,其比较稳定的prefork模式为多进程模式,需要经常派生子进程,所消耗的CPU等服务器资源要比nginx高的多.

select 和epoll效率差的原因: select是轮询、epoll是触发式的,所以效率高。单单这样讲,那能懂了才见鬼了.好...我们暂且客观的记住这句话.

先说Select: 
1.Socket数量限制:该模式可操作的Socket数由FD_SETSIZE决定,内核默认32*32=1024. 
2.操作限制:通过遍历FD_SETSIZE(1024)个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍.

后说Poll: 
1.Socket数量几乎无限制:该模式下的Socket对应的fd列表由一个数组来保存,大小不限(默认4k). 
2.操作限制:同Select.

再说:Epoll: 
1.Socket数量无限制:同Poll 
2.操作无限制:基于内核提供的反射模式,有活跃Socket时,内核访问该Socket的callback,不需要遍历轮询. 但是当所有Socket都活跃的时候,这时候所有的callback都被唤醒,会导致资源的竞争.既然都是要处理所有的Socket,那么遍历是最简单最有效的实现方式.

举例来说: 
对于IM服务器,服务器和服务器之间都是长链接,但数量不多,一般一台60\70个,比如采用ICE这种架构设计,但请求相当频繁和密集,这时候通过反射唤醒callback不一定比用select去遍历处理更好. 
对于web portal(门户)服务器,都是浏览器客户端发起的http短链接请求,数量很大,好一点的网站动辄每分钟上千个请求过来,同时服务器端还有更多的闲置等待超时的Socket,这时候没必要把全部的Socket都遍历处理,因为那些等待超时的请求是大多数的,这样用Epoll会更好.

支持一个进程打开大数目的socket描述符
   select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是1024。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远 比不上线程间同步的高效,所以也不是一种完美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
IO效率不随FD数目增加而线性下降
  传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延时, 任一时间只有部分的socket是“活跃”的,但是select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对“活跃”的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有“活跃”的socket才会主动的去调用 callback函数,其他idle状态socket则不会,在这点上,epoll实现了一个“伪”AIO,因为这时候推动力在os内核。在一些 benchmark中,如果所有的socket基本上都是活跃的---比如一个高速LAN环境,epoll并不比select/poll有什么效率,相反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。 
  使用mmap加速内核与用户空间的消息传递。 
  这点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。而如果你想我一样从2.5内核就关注epoll的话,一定不会忘记手工 mmap这一步的。
内核微调
  这一点其实不算epoll的优点了,而是整个linux平台的优点。也许你可以怀疑linux平台,但是你无法回避linux平台赋予你微调内核的能力。比如,内核TCP/IP协议栈 使用内存池管理sk_buff结构,那么可以在运行时期动态调整这个内存pool(skb_head_pool)的大小--- 通过echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函数的第2个参数(TCP完成3次握手 的数据包队列长度),也可以根据你平台内存大小动态调整。更甚至在一个数据包面数目巨大但同时每个数据包本身大小却很小的特殊系统上尝试最新的NAPI网 卡驱动架构。

select模式低效的原因
select 模式低效是由select的定义所决定的,与操作系统实现无关,任何内核在实现select时必须做轮循,才能知道这些socket的情况,这是会消耗 cpu的。此外,当你拥有一个很大socket集的时候,尽管任一时间只有小部分的socket是"活跃"的,但每次你都不得不将所有的socket填入到一个FD_SET中,这也会消耗一些cpu,并且当select返回后,处理业务时你可能还需要做“上下文映射”,同样也会有一些性能影响,因此 select比epoll相对低效。
epoll的适用情景就是大量的socket,但是活跃多不是很高的情况。   
还有 kqueue,实际上有不少服务器是基于 BSD 开发的
kqueue 和 epoll 类似,据说效率上稍微高一些,不过没比较过

多路IO复用模型 select epoll 等相关推荐

  1. Python多路IO复用之select

    前言 这几年一直在it行业里摸爬滚打,一路走来,不少总结了一些python行业里的高频面试,看到大部分初入行的新鲜血液,还在为各样的面试题答案或收录有各种困难问题 于是乎,我自己开发了一款面试宝典,希 ...

  2. Redis采用单线程+多路IO复用技术

    多路复用指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就位,则返回,否则阻塞直到超时.得到就绪状态后进行真正 ...

  3. IO复用之select、poll、epoll模型

    因为select.poll.epoll都是IO复用模型的解决方案,它们最终的目标都是为了解决单个应用进程(从应用的角度来看这里也可以理解为单个线程,从系统的角度来看这里面向的就是应用进程)能同时处理多 ...

  4. Linux网络编程---I/O复用模型之epoll

    https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程-I/O复用模型之epoll 1. epoll模型简介 epoll是Li ...

  5. 多路IO复用(Linux)

    一.介绍 多路IO复用,是通过系统底层对描述符事件的检测,通过描述符集合返回,通过描述符集合实现对单一句柄操作 多路IO复用有三种: (1)select (2)poll (3)epoll 对比: 特点 ...

  6. Redis之单线程+多路IO复用技术

    Redis 是单线程+多路IO复用技术 多路复用:使用一个线程来检查多个文件描述符的就绪状态 如果有一个文件描述符就绪,则返回 否则阻塞直到超时 得到就绪状态后进行真正的操作可以在同一个线程里执行,也 ...

  7. Redis网络多路IO复用以及底层原理

    老早听说过Redis是单线程,但指的是什么单线程,为什么单线程,底层实现原理是什么? 单线程指的是Redis中处理网络请求的模块是单线程处理的,并非指整一个Redis软件都是单线程,肯定有其它线程做其 ...

  8. Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合

    上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型. 阻塞IO 过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器为例,我 ...

  9. Redis采用的单线程+多路IO复用

    为什么redis是单线程的? 首先并不是高性能服务器都是多线程来实现的,因为reids的核心就是数据在内存中,他单线程的去操作就是效率最高的.单线程可以避免上下文的切换和锁的竞争. 一次CPU上下文切 ...

最新文章

  1. 【HTML5游戏开发】简单的《找不同汉字版》,来考考你的眼力吧
  2. 台式计算机无线设置,台式电脑怎么设置无线网络?
  3. CodeForces 66C Petya and File System (实现)
  4. Java查找数组重复元素,并打印重复元素、重复次数、重复元素位置
  5. (time.h) 自己用
  6. 读写分离,读写分离死锁解决方案,事务发布死锁解决方案,发布订阅死锁解决方案|事务(进程 ID *)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务...
  7. 剑指Offer(java版):第一个只出现一次的字符
  8. vue 安装element_vue实战开发007:vue引入Element-UI并配置路由
  9. java与c基本数据类型比较,C++与Java基本数据类型比较
  10. 电子政务发展现状的调研分析(转)
  11. 数据结构1800题-错题集-第一章
  12. ADC 前端电路的五个设计步骤(转载)
  13. 云栖·武汉峰会 | 现场:阿里云为何频打“自研”牌?
  14. vs2008安装失败解决办法
  15. 速达pro服务器显示试用,速达v3-pro商业版突然变成试用版了,加密狗的灯不亮了,是什么原因- _0...
  16. ImageIO: PNG invalid PNG file: iDOT doesn't point to valid IDAT chunk
  17. 计算机音量程序是哪个键,电脑如何设置音量快捷键
  18. Spark优化——推测执行机制
  19. 《Storm实时数据处理》一2.3 创建日志Spout
  20. 我要悄悄学习,做一个浪漫的程序员

热门文章

  1. 2017年计算机四级试题,2017年全国计算机四级考试模拟试题与答案
  2. 英特尔cpu发布时间表_英特尔第11代桌面CPU将会支持PCIe4.0,Z490主板或可支持PCIe4.0...
  3. 笔记本蓝牙显示输入码无效_如何凭借一把键盘游走桌面?米物蓝牙双模键盘
  4. MySQL面试题 | 附答案解析(十六)
  5. Python Qt GUI设计:QTableView、QListView、QListWidet、QTableWidget、QTreeWidget和QTreeWidgetltem表格和树类(提升篇—1)
  6. 力扣(LeetCode)刷题,简单+中等题(第31期)
  7. 自定义类型数组的初始化
  8. mysql版本不一致会导致uuid_MySQL性能优化和高可用架构建议
  9. 文件系统类型是ntfs无法确定卷版本和状态_硬盘写到一半时断电,文件系统里会发什么?...
  10. GVINS:基于GNSS视觉惯性紧耦合的平滑状态估计方法