看下Python select 的c 源码
|
|
调用了 c 的select。接着一步步查select 的内核实现
|
|
|
|
fd_set_bits 是6个bitmaps,前三个是用户传来的bitmaps,后三个是用来存储do_select执行结果。
get_fd_set, 复制用户的fd_set, zero_fd_set, 先把用来存结果的先清零。
|
|
真行的执行是在do_select实现的。
|
|
先看for (;;)
这个死循环里的,先说这里从Python就开始传的参数n,这个是最大max_fd, 因为我们知道select 监听的 fds_bits 一共是1024位 #define __FD_SETSIZE 1024
指定了最大的fd n,可以避免每次循环1024个,这样只需要每次循环到fd = n 时就可以了,节约资源。
|
|
这两层循环遍历了所有fd_set 的 bit, 对每个fd
mask = (*f_op->poll)(file, retval ? NULL : wait);
调用 file 的poll。这里poll 不再继续展开介绍,大体的功能是检查当前的文件状态,返回一个mask描述当前的操作是否就绪。我们把这个标志mask的结果写回结果的fd_set。
如果当前的mask 表示 read 操作就绪,(mask & POLLIN_SET)
那么就写到关心 read 操作的 fd_set中 res_in |= bit;
遍历了一圈如果有一个事件发生 retval 就有了值或者timeout 超时了,退出循环,通知上一层。 如果一个关系的事件都没有到来,则进入休眠timeout = schedule_timeout(timeout);
。
OK,我们总结一下
- select只能监听有限个socket,主要因为
__FD_SETSIZE
限制 - select 会轮训一遍socket(其实就轮询到max_fd不会轮询完 __FD_SETSIZE)但不会一直轮询所有的socket,如果一次轮询之后没有结果,会进入休眠,节约cpu资源