笔记-select,poll,epoll

1.      I/O多路复用

I/O多路复用是指:通过一种机制或一个进程,可以监视多个文件描述符,一旦描述符就绪(写或读),能够通知程序进行相应的读写操作。

linux中的select,poll,epoll都是IO多路复用的具体实现。

1.1.  select

select最早出现在4.2BSD中,通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使进程可以获得这些文件描述符而进行后续操作。

select的缺点:

  1. 每次调用select,需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大;
  2. 每次调用select后需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大;
  3. 单个进程能够监视的文件描述符数量存在最大限制,在linux上一般为1024; select返回的是含有整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件;

1.2.    poll

poll在1986年诞生于System V Release 3,它的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。因为pollfd是链表式的,所以poll没有最大文件描述符数量的限制,除了这一点,其它特性和select一样。

poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。另外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。

1.3.    epoll

在linux2.6(准确来说是2.5.44)由内核直接支持的方法。epoll解决了select和poll的缺点。

  1. 最大描述符数量限制,epoll没有这个限制,它所支持的fd上限是最大可以打开文件的数目,具体数目可以cat /proc/sys/fs/file-max查看,一般来说这个数目和系统内存关系比较大;
  2. 重复拷贝问题:每次注册新的事件到epoll中时,会把所有的fd拷贝进内核,而不是在等待的时候重复拷贝,保证了每个fd在整个过程中只会拷贝1次。
  3. 遍历问题:epoll的解决方法不像select和poll每次对所有fd进行遍历轮询所有fd集合,而是在注册新的事件时,为每个fd指定一个回调函数,当设备就绪的时候,调用这个回调函数,这个回调函数就会把就绪的fd加入一个就绪表中。(所以epoll实际只需要遍历就绪表)。

epoll同时支持水平触发和边缘触发:

  1. 水平触发(level-triggered):只要满足条件,就触发一个事件(只要有数据没有被获取,内核就不断通知你)。e.g:在水平触发模式下,重复调用epoll.poll()会重复通知关注的event,直到与该event有关的所有数据都已被处理。(select, poll是水平触发, epoll默认水平触发)
  2. 边缘触发(edge-triggered):每当状态变化时,触发一个事件。e.g:在边沿触发模式中,epoll.poll()在读或者写event在socket上面发生后,将只会返回一次event。调用epoll.poll()的程序必须处理所有和这个event相关的数据,随后的epoll.poll()调用不会再有这个event的通知。

2. 附录

2.1.  水平触发与边缘触发

在linux的IO多路复用中有水平触发,边缘触发两种模式,这两种模式的区别如下:

水平触发:如果文件描述符已经就绪可以非阻塞的执行IO操作了,此时会触发通知.允许在任意时刻重复检测IO的状态,没有必要每次描述符就绪后尽可能多的执行IO.select,poll就属于水平触发.

边缘触发:如果文件描述符自上次状态改变后有新的IO活动到来,此时会触发通知.在收到一个IO事件通知后要尽可能多的执行IO操作,因为如果在一次通知中没有执行完IO那么就需要等到下一次新的IO活动到来才能获取到就绪的描述符.信号驱动式IO就属于边缘触发.

epoll既可以采用水平触发,也可以采用边缘触发.

举例说明:一个管道收到了1kb的数据,epoll会立即返回,此时读了512字节数据,然后再次调用epoll.这时如果是水平触发的,epoll会立即返回,因为有数据准备好了.如果是边缘触发的不会立即返回,因为此时虽然有数据可读但是已经触发了一次通知,在这次通知到现在还没有新的数据到来,直到有新的数据到来epoll才会返回,此时老的数据和新的数据都可以读取到(当然是需要这次你尽可能的多读取).

最新文章

  1. MVC学习系列10---验证系列之服务器端验证
  2. web前端程序员真的值这么多钱吗?
  3. HTML 教程延伸阅读:改变文本的外观和含义
  4. git tool
  5. With语句以及@contextmanager的语法解析
  6. C语言实现二叉树-04版
  7. 10SpringMvc_springmvc快速入门小案例(注解版本)
  8. LVS负载均衡集群服务搭建详解(一)
  9. 导出excel部分代码
  10. ASP.NET简单登录注册实例
  11. c++中智能输出文件
  12. tyvj 1729 文艺平衡树
  13. 通用的 makefile 小工具分享 - Easymake 使用说明
  14. JSON 日期格式带 T 问题
  15. [LeetCode]题解(python):017-Letter Combinations of a Phone Number
  16. iOS开发之SDWebImage详解
  17. HDU 5631 Rikka with Graph
  18. 设置input框文字垂直居中和宽度
  19. 如何编写gitignore文件
  20. PHP整理--PHP语句流程

热门文章

  1. Android Studio使用OpenCV的配置方法
  2. Quick How-To deny/allow IP using iptables
  3. c\c++数据类型存储
  4. centos6.5_64bit-禅道安装及数据库操作
  5. vos话务抽查小方法
  6. JavaRebel 2.0 发布,一个JVM插件
  7. POJ-3111 K Best---二分求最大化平均值
  8. 轻量级HTTP服务器Nginx(配置与调试Nginx维护Nginx)
  9. Spring MVC的一些学习笔记-入门配置和HttpMessageConverter
  10. p2597 灾难