selectors ---高级I/O复用模块详解

一、前言

1.I/O多路复用

- 大多数操作系统都支持select和poll
- Linux2.5+支持epoll
- BSD、Mac支持kqueue
- Solaris支持/dev/poll
- Windows支持IOCP

2.select、poll、epoll的三者的区别:

①select

目前几乎支持所有的平台。
默认单个进程能够监视的文件描述符的数量存在最大限制,在linux上默认只支持1024个socket
可以通过修改宏定义或重新编译内核(修改系统最大支持的端口数)的方式提升这一限制。
内核准备好数据后通知用户有数据了,但不告诉用户是哪个连接有数据,用户只能通过轮询的方式来获取数据。

假定select让内核监视100个socket连接,当有1个连接有数据后,内核就通知用户100个连接中有数据了,但是不告诉用户是哪个连接有数据了,此时用户只能通过轮询的方式一个个去检查然后获取数据。
这里是假定有100个socket连接,那么如果有上万个,上十万个呢?那你就得轮询上万次,上十万次,而你所取的结果仅仅就那么1个。这样就会浪费很多没用的开销。

只支持水平触发

每次调用select,都需要把fd(文件描述符)集合从用户态拷贝到内核态,这个开销在fd很多时会很大。
同时每次调用select都需要在内核遍历所传递过来的所有fd,这个开销在fd很大时也会很大。

②poll

与select没有本质上的差别,仅仅是没有了最大文件描述符数量的限制

同样只支持水平触发
只是一个过渡版本,很少用。

③epoll

Linux2.6开始才出现的epoll,具备了select和poll的一切优先,是公认性能最好的多路I/O就绪通知方法

没有最大文件描述符数量的限制
同时支持水平触发和边缘触发

不支持windows平台

内核准备好数据以后会通知用户哪个连接有数据了。
I/O效率不随着fd数目的增加而线性下降。
使用mmap加速内核与用户空间的消息传递。

3.水平触发和边缘触发

①水平触发

将就绪的文件描述符告诉进程后,如果进程没有对其进行I/O操作,那么下次epoll时将再次报告这些文件描述符,称为水平触发。

②边缘触发

只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果没有采取行动,那么它将不会再次告知,这种方式称为边缘触发。

4.select和epoll的特点

1.select通过select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述从而进行后续的读写操作。
由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,这也浪费了一定的开销。

2.epoll只告知那些就绪的文件描述符,而且当我们调用epoll_wait获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中一次取得相应数量的文件描述符即可,这里也是用了内存映射技术(mmap),这样便彻底省掉了这些描述符在系统调用时复制的开销。
另一个本质的改进在意epoll采用基于时间的就绪通知方式。在select/poll中,进程只有在调用一定的方法之后,内核才对所有监视的文件描述符进行扫描,而epoll事件事先通过epoll_ctl来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait时变得到通知

二、概述

它封装了I/O对路复用中的select和epoll,能够更快,更方便的实现多并发效果。

它定义了一个BaseSelector抽象基类,以及几个具体实现(KqueueSelector, EpollSelector…),可以等待多核文件I/O的就绪通知。

三、selectors库的一些使用方法

1.selectors库的一些常用类和方法

类的层次结构

BaseSelector
+-- SelectSelector
+-- PollSelector
+-- EpollSelector
+-- DevpollSelector
+-- KqueueSelector

1.1 创建selector对象
class selectors.DefaultSelector是当前平台上可用的系统调用最有效的实现。

if 'KqueueSelector' in globals():
    DefaultSelector = KqueueSelector
elif 'EpollSelector' in globals():
    DefaultSelector = EpollSelector
elif 'DevpollSelector' in globals():
    DefaultSelector = DevpollSelector
elif 'PollSelector' in globals():
    DefaultSelector = PollSelector
else:
    DefaultSelector = SelectSelector

注意,由于这个库没有实现windows下的IOCP, 所以windows下只能退化为select

创建一个SelectSelector实例对象

In [1]: import selectors

In [2]: selector = selectors.DefaultSelector()
   ...: 

In [3]: selector
Out[3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值