IO多路复用

IO多路复用

IO多路复用就是通过一种机制,同时监视多个文件描述符,一旦某个文件描述符就绪(比如读就绪或写就绪),会通知应用程序进行相应的处理。
select、poll、epoll本质上都是同步IO,它们都需要在事件就绪后,由应用程序自己进行读写。而异步IO不需要应用程序自己进行读写,异步IO实现负责把数据从内核拷贝到用户空间。

Linux提供了select、poll、epoll,来实现IO多路复用机制,下面会分别对它们进行简要的说明。


select、poll

关于select、poll的原型和详细说明,请点击这个链接
在这里,只对select和poll的执行过程,进行简要的说明:

  • 将文件描述符集合从用户空间拷贝到内核空间
  • 对每一个描述符进行轮询,并记录临时结果
    • 如果有事件发生,则将临时结果写到用户空间并返回
    • 如果没有事件发生,那么sleep到超时,然后再进行一次检查,这次检查之后,无论是否有事件发生,都返回
  • select或poll返回后,需要逐一检查关注的描述符是否有事件发生

epoll

关于epoll的详解,请点击这个链接

epoll的使用过程如下:

  • 通过epoll_create创建epoll描述符
  • 通过epoll_ctl向epoll描述符中,添加、修改或删除事件
  • 通过epoll_wait收集发生事件的描述符

与select、poll相比,epoll有下面的特点:

  • 不必每次都向内核拷贝文件描述符。当通过epoll_ctl添加一个文件描述符之后,它就与epoll描述符关联起来了
  • epoll不是通过轮询的方式来检查文件描述符的。所有添加到epoll中的事件都会与设备驱动程序建立回调关系,当相应的事件发生时,回调函数负责把事件添加到就绪事件链表。当调用epoll_wait检查是否有事件发生时,只需要检查就绪事件链表即可

水平触发和边缘触发

epoll有水平触发和边缘触发两种模式。水平触发是默认模式,边缘触发是高速模式。在水平触发模式下,如果一个描述符有数据可读,那么每次调用epoll_wait都会返回该描述符的事件。而在边缘触发模式下,只会提醒一次,直到有新的数据流入。因此在边缘触发模式下,读一个描述符一定要读空它的buffer,也就是一直读到read的返回值小于它的请求值,或遇到EAGAIN错误(读非阻塞socket的时候,如果输入缓冲区中没有数据,就会出现EAGAIN错误,意思是告诉应用程序,再读一次或许就有数据了)。


文件描述符

当进程打开或新建一个文件的时候,内核会返回一个文件描述符,文件描述符是一个非负整数,取值范围是0到max open files。
内核会为每个进程维护一个 保存该进程打开的文件的 记录表,文件描述符就是这个记录表中的索引值,内核利用文件描述符来访问文件。
通常,标准输入的文件描述符是0,标准输出的文件描述符是1,标准错误输出的文件描述符是2。


epoll in Python

Python标准库的select模块,提供了访问 操作系统的IO多路复用接口的 功能。select的文档在:https://docs.python.org/2.7/library/select.html
下面主要介绍其中关于epoll的部分:

  • select.epoll([sizehint=-1])
    返回一个epoll对象。事件掩码的含义如下:
    • EPOLLIN - 有数据可读
    • EPOLLOUT - 可写
    • EPOLLPRI - 有紧急数据可读
    • EPOLLERR - 在相关联的文件描述符上发生了错误
    • EPOLLHUP - 在相关联的文件描述符上发生了关闭事件
    • EPOLLET - 设置边缘触发行为,默认是水平触发行为
    • EPOLLONESHOT - 设置one-shot行为,在一次事件被拉出之后,文件描述符在内部被关闭
  • epoll.close()
    关闭epoll对象的控制文件描述符
  • epoll.fileno()
    返回控制描述符的数字表示
  • epoll.fromfd(fd)
    从一个给定的文件描述符创建epoll对象
  • epoll.register(fd, [eventmask])
    把一个文件描述符注册到epoll对象。注意:注册一个已经注册过的文件描述符会引发IOError。
  • epoll.modify(fd, eventmask)
    修改一个已经注册过的文件描述符
  • epoll.unregister(fd)
    从epoll对象移除一个已经注册的文件描述符
  • epoll.poll([timeout=-1[, maxevents=-1]])
    收集发生事件的文件描述符,timeout的单位是秒

参考文档

感谢浏览tim chow的作品!

如果您喜欢,可以分享到: 更多

如果您有任何疑问或想要与tim chow进行交流

可点此给tim chow发信

如有问题,也可在下面留言: