概念

IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程

通俗理解(摘自网上一大神)

这些名词比较绕口,理解涵义就好。一个epoll场景:一个酒吧服务员(一个线程),前面趴了一群醉汉,突然一个吼一声“倒酒”(事件),你小跑过去给他倒一杯,然后随他去吧,突然又一个要倒酒,你又过去倒上,就这样一个服务员服务好多人,有时没人喝酒,服务员处于空闲状态,可以干点别的玩玩手机。至于epoll与select,poll的区别在于后两者的场景中醉汉不说话,你要挨个问要不要酒,没时间玩手机了。io多路复用大概就是指这几个醉汉共用一个服务员。

select

进程指定内核监听哪些文件描述符(最多监听1024个fd)的哪些事件,当没有文件描述符事件发生时,进程被阻塞;当一个或者多个文件描述符事件发生时,进程被唤醒。

当我们调用select()时:

  1 上下文切换转换为内核态

  2 将fd从用户空间复制到内核空间

  3  内核遍历所有fd,查看其对应事件是否发生

  4  如果没发生,将进程阻塞,当设备驱动产生中断或者timeout时间后,将进程唤醒,再次进行遍历

  5 返回遍历后的fd

  6  将fd从内核空间复制到用户空间

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

fd_r_list, fd_w_list, fd_e_list = select.select(rlist, wlist, xlist, [timeout])

 

参数: 可接受四个参数(前三个必须)

rlist: wait until ready for reading

wlist: wait until ready for writing

xlist: wait for an “exceptional condition”

timeout: 超时时间

返回值:三个列表

 

select方法用来监视文件描述符(当文件描述符条件不满足时,select会阻塞),当某个文件描述符状态改变后,会返回三个列表

1、当参数1 序列中的fd满足“可读”条件时,则获取发生变化的fd并添加到fd_r_list中

2、当参数2 序列中含有fd时,则将该序列中所有的fd添加到 fd_w_list中

3、当参数3 序列中的fd发生错误时,则将该发生错误的fd添加到 fd_e_list中

4、当超时时间为空,则select会一直阻塞,直到监听的句柄发生变化

   当超时时间 = n(正整数)时,那么如果监听的句柄均无任何变化,则select会阻塞n秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。

在服务端我们可以看到,我们需要不停的调用select, 这就意味着:

  1  当文件描述符过多时,文件描述符在用户空间与内核空间进行copy会很费时

  2  当文件描述符过多时,内核对文件描述符的遍历也很浪费时间

  3  select最大仅仅支持1024个文件描述符

epoll是select和poll改进后的结果,相比下epoll具有以下优点:

1、支持一个进程打开的socket描述符(FD)不受限制(仅受限于操作系统的最大文件句柄数)

select最大的缺陷就是单个进程所打开的FD是有一定限制的,它由FD_SETSIZE设置,默认值是1024,epoll并没有这个限制,它所支持的FD上限是操作系统的最大文件句柄数,这个数字远远大于1024

2、I/O效率不会随着FD数目的增加而线性下降

epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时,会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次

传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,由于网络延时或者链路空闲,任一时刻只有少部分的socket是“活跃”的,但是select/poll每次调用都会线性扫描全部集合,导致效率呈现线性下降。epoll不存在这个问题,它只会对“活跃”的socket进行操作-这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的,那么,只有“活跃”的socket才会主动的去调用callback函数,其他idle状态socket则不会。在这点上,epoll实现了一个伪AIO

3、使用mmap加速内核与用户空间的消息传递

epoll会在epoll_ctl时把指定的fd遍历一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd

无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存复制就显得非常重要,epoll是通过内核和用户空间mmap使用同一块内存实现。

4、epoll的API更加简单

用来克服select/poll缺点的方法不只有epoll,epoll只是一种Linux的实现方案。在freeBSD下有kqueue,而dev/poll是最古老的Solaris的方案,使用难度依次递增。但epoll更加简单。

epoll

python中的select模块专注于I/O多路复用,提供了select  poll  epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue方法(freeBSD系统)

select.epoll(sizehint=-1, flags=0) 创建epoll对象

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

epoll.close()

Close the control file descriptor of the epoll object.关闭epoll对象的文件描述符

epoll.closed

True if the epoll object is closed.检测epoll对象是否关闭

epoll.fileno()

Return the file descriptor number of the control fd.返回epoll对象的文件描述符

epoll.fromfd(fd)

Create an epoll object from a given file descriptor.根据指定的fd创建epoll对象

epoll.register(fd[, eventmask])

Register a fd descriptor with the epoll object.向epoll对象中注册fd和对应的事件

epoll.modify(fd, eventmask)

Modify a registered file descriptor.修改fd的事件

epoll.unregister(fd)

Remove a registered file descriptor from the epoll object.取消注册

epoll.poll(timeout=-1, maxevents=-1)

Wait for events. timeout in seconds (float)阻塞,直到注册的fd事件发生,会返回一个dict,格式为:{(fd1,event1),(fd2,event2),……(fdn,eventn)}

事件:

1

2

3

4

5

6

7

8

9

10

11

12

EPOLLERR = 8               ----发生错误

EPOLLET = 2147483648       ----默认为水平触发,设置该事件后则边缘触发

EPOLLHUP = 16              ----挂起状态

EPOLLIN = 1                ----可读

EPOLLMSG = 1024            ----忽略

EPOLLONESHOT = 1073741824  ----一次性行为。在退出一个事件后,FD内部禁用

EPOLLOUT = 4               ----可写

EPOLLPRI = 2               ----紧急可读

EPOLLRDBAND = 128          ----读取优先

EPOLLRDNORM = 64           ----相当于epollin

EPOLLWRBAND = 512          ----写入优先

EPOLLWRNORM = 256          ----相当于epollout

水平触发和边缘触发:

EPOLL事件有两种模型:
Edge Triggered (ET) 边缘触发只有数据到来,才触发,不管缓存区中是否还有数据。
Level Triggered (LT) 水平触发只要有数据都会触发。

LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表.

优点:当进行socket通信的时候,保证了数据的完整输出,进行IO操作的时候,如果还有数据,就会一直的通知你。

缺点:由于只要还有数据,内核就会不停的从内核空间转到用户空间,所有占用了大量内核资源,试想一下当有大量数据到来的时候,每次读取一个字节,这样就会不停的进行切换。内核资源的浪费严重。效率来讲也是很低的。

ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知。请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once).

优点:每次内核只会通知一次,大大减少了内核资源的浪费,提高效率。

缺点:不能保证数据的完整。不能及时的取出所有的数据。

应用场景: 处理大数据。使用non-block模式的socket。

linux IO多路复用 select epoll相关推荐

  1. Linux IO多路复用之epoll网络编程(含源码)

    前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一 ...

  2. Linux IO多路复用之epoll网络编程,高并发的使用例子 (含源码)

    本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一行,然 ...

  3. Linux之poll/select/epoll代码示例

    Linux poll and epoll poll 问题:假如应用需要根据IO的状态来读或写多个IO,如何处理?如果是一个进程处理,一个一个IO的处理,那么就势必会出现阻塞等待某个IO的过程,此时就可 ...

  4. linux io多路复用详解,Linux系统中IO多路复用

    文章目录 1 什么是IO多路复用 1.1 阻塞IO模型 1.2 非阻塞IO模型 1.3 IO复用模型 1.4 信号驱动IO模型 1.5 异步IO模型 2 IO多路复用,epoll 1 什么是IO多路复 ...

  5. 使用多线程还是用IO复用select/epoll? epoll 或者 kqueue 的原理是什么?

    原作者:蓝形参 原文:http://www.zhihu.com/question/20114168/answer/14024115 使用多线程还是用IO复用select/epoll? 多线程模型适用于 ...

  6. IO多路复用之epoll总结 http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html

    IO多路复用之epoll总结 http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html

  7. Linux IO多路复用之Select简史

    内容目录 前言早期的UnixTCP/IP诞生后终端复用套接字章节回顾结论引用 前言 最近我一直在思考 Linux 中的多路复用,即 epoll(7)[1]系统调用.我很好奇 epoll与Windows ...

  8. python3 异步 非阻塞 IO多路复用 select poll epoll 使用

    有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的. 下面记录下分别基于Select/Poll/Epoll的echo ser ...

  9. linux平台IO多路复用 select接口使用例子

    这几天在学习net-snmp源码,里面封装了很多select函数调用,这里记录一下linux上select的用法以及相关接口. 先看接口: //头文件 #include <sys/select. ...

最新文章

  1. 关于百度分享——bdCustomStyle一点bug
  2. 纪念:2006年我在51CTO的第一帖
  3. 简单易懂的多线程(通过实现Runnable接口实现多线程)
  4. RobotFramework读取mysql和oracle数据库
  5. mybatis中的#{}和${}区别,和使用场景
  6. 微服务架构案例(05):SpringCloud 基础组件应用设计
  7. pg批量插入_在PostgreSQL中批量/批量更新/提升
  8. webpack异步加载业务模块
  9. VirtualBox中安装Android-x86详解
  10. 输入输出知识点和问题超全总结(持续更新中)
  11. 学习s3c2440的随笔笔记
  12. appbase_使用Appbase.io和JavaScript构建类似于Live Search Feed的Twitter
  13. OpenJudge 百练 2787 算24
  14. 官网下载Eclipse详细步骤
  15. word文档怎么调成黑底白字
  16. 走近棒球运动·底特律老虎队·MLB棒球创造营
  17. oracle 查询group by的字段之外的字段
  18. JAVA 使用if选择结构判断某一年份是否是闰年。闰年的条件:普通闰年:能被4整除但不能被100整除的年份为普通闰年。(如2004年就是闰年);世纪闰年:能被400整除的为世纪闰年。
  19. 如何精准地识别摄像头前方的物体类型和测距?
  20. 软件测试周刊(第20期):恐惧,来自只思考却不行动

热门文章

  1. 几种USB控制器类型:OHCI,UHCI,EHCI,XHCI
  2. 记录Flex布局的属性
  3. 交通部:将从五方面推进京津冀暨雄安新区交通建设
  4. Mac OS Yosemite 文件批量重命名
  5. HTTP协议详解【转】
  6. 编译预处理 -- 带参数的宏定义--【原创】
  7. 库(静态库和动态库)
  8. sysbench-系统、数据库压力测试工具
  9. java 判断一个字符串是否为纯数字
  10. C# 系统应用之清除Cookies、IE临时文件、历史记录 转载