简介

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

select方法

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

当我们调用select()时:

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

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

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

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

5、返回遍历后的fd

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

fd:file descriptor 文件描述符

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实现一个可并发的服务端

import socket
import selects = socket.socket()
s.bind(('127.0.0.1',8888))
s.listen(5)
r_list = [s,]
num = 0
while True:rl, wl, error = select.select(r_list,[],[],10)num+=1print('counts is %s'%num)print("rl's length is %s"%len(rl))for fd in rl:if fd == s:conn, addr = fd.accept()r_list.append(conn)msg = conn.recv(200)conn.sendall(('first----%s'%conn.fileno()).encode())else:try:msg = fd.recv(200)fd.sendall('second'.encode())except ConnectionAbortedError:r_list.remove(fd)s.close()
import socketflag = 1
s = socket.socket()
s.connect(('127.0.0.1',8888))
while flag:input_msg = input('input>>>')if input_msg == '0':breaks.sendall(input_msg.encode())msg = s.recv(1024)print(msg.decode())s.close()

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

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

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

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

poll与select相差不大,本文不作介绍

epoll方法:

epoll很好的改进了select:

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

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

3、epoll对文件描述符没有额外限制

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

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)}

事件:

EPOLLIN Available for read 可读 状态符为1

EPOLLOUT Available for write 可写 状态符为4

EPOLLPRI Urgent data for read

EPOLLERR Error condition happened on the assoc. fd 发生错误 状态符为8

EPOLLHUP Hang up happened on the assoc. fd 挂起状态

EPOLLET Set Edge Trigger behavior, the default is Level Trigger behavior 默认为水平触发,设置该事件后则边缘触发

EPOLLONESHOT Set one-shot behavior. After one event is pulled out, the fd is internally disabled

EPOLLRDNORM Equivalent to EPOLLIN

EPOLLRDBAND Priority data band can be read.

EPOLLWRNORM Equivalent to EPOLLOUT

EPOLLWRBAND Priority data may be written.

EPOLLMSG Ignored.

水平触发和边缘触发:

Level_triggered(水平触发,有时也称条件触发):当被监控的文件描述符上有可读写事件发生时,epoll.poll()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll.poll()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!! 优点很明显:稳定可靠

Edge_triggered(边缘触发,有时也称状态触发):当被监控的文件描述符上有可读写事件发生时,epoll.poll()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll.poll()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!缺点:某些条件下不可靠

epoll实例:

import socket
import selects = socket.socket()
s.bind(('127.0.0.1',8888))
s.listen(5)
epoll_obj = select.epoll()
epoll_obj.register(s,select.EPOLLIN)
connections = {}
while True:events = epoll_obj.poll()for fd, event in events:print(fd,event)if fd == s.fileno():conn, addr = s.accept()connections[conn.fileno()] = connepoll_obj.register(conn,select.EPOLLIN)msg = conn.recv(200)conn.sendall('ok'.encode())else:try:fd_obj = connections[fd]msg = fd_obj.recv(200)fd_obj.sendall('ok'.encode())except BrokenPipeError:epoll_obj.unregister(fd)connections[fd].close()del connections[fd]s.close()
epoll_obj.close()
import socketflag = 1
s = socket.socket()
s.connect(('127.0.0.1',8888))
while flag:input_msg = input('input>>>')if input_msg == '0':breaks.sendall(input_msg.encode())msg = s.recv(1024)print(msg.decode())s.close()

深入理解python中的select模块相关推荐

  1. python select模块_深入理解python中的select模块

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

  2. cx_oracle主备服务器,怎么在Python中使用cx_Oracle模块对Oracle数据库进行操作

    怎么在Python中使用cx_Oracle模块对Oracle数据库进行操作 发布时间:2021-03-17 16:32:34 来源:亿速云 阅读:67 作者:Leah 本篇文章为大家展示了怎么在Pyt ...

  3. python怎么导入包-如何理解Python中包的引入

    Python的from import *和from import *,它们的功能都是将包引入使用,但是它们是怎么执行的以及为什么使用这种语法呢? 从一模块导入全部功能 from import * me ...

  4. 如何简单地理解Python中的if __name__ == '__main__'

    如何简单地理解Python中的if __name__ == '__main__' 文章目录: 一.摘要 二. 程序入口 虽然已经知道这个具体的用法,但是这篇文章有很多细节写的还是很好,决定转载一下,日 ...

  5. python中的log模块笔记

    日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模块日志流处理流程 使用logging四大组件记录日志 配置logging的几种方式 向日志输出中添 ...

  6. 深入理解Python中的全局解释锁GIL

    深入理解Python中的全局解释锁GIL 转自:https://zhuanlan.zhihu.com/p/75780308 注:本文为蜗牛学院资深讲师卿淳俊老师原创,首发自公众号https://mp. ...

  7. 数据科学 IPython 笔记本 9.3 理解 Python 中的数据类型

    9.3 理解 Python 中的数据类型 本节是<Python 数据科学手册>(Python Data Science Handbook)的摘录. 译者:飞龙 协议:CC BY-NC-SA ...

  8. python变量的理解_如何理解Python中的变量

    在本篇文章里小编给大家分享的是关于Python中变量是什么意思的相关基础知识点,需要的朋友们可以学习下. 变量 在Python中,存储一个数据,需要定义一个变量 number1 = 1 #numbe1 ...

  9. Python中的warnings模块详细阐述

    Python中的warnings模块详细阐述 异常和警告 warnings - 非致命提醒 警告类别 警告过滤器 默认警告过滤器 可用函数 生成警告 使用模式过滤 重复警告 其他消息传递函数 由于在读 ...

最新文章

  1. Unix/Linux环境C编程入门教程(39) shell命令之系统管理
  2. Android使用adb抓完整Log
  3. tensorflow中tf.random_normal和tf.truncated_normal的区别
  4. pytorch已经安装成功了为什么不能使用import_使用auto keras的过程
  5. 如何处理JavaScript中的事件处理(示例和全部)
  6. 将进酒,如果李白也编程
  7. 利用模态DIV结合UpdateProgress防止页面重复提交
  8. 引言:扇贝 2017 服务端技术回顾
  9. vue-cli 最强指南
  10. 基于SSM+MySQL的实现的汽车门店管理平台系统
  11. 【数据库】SQL中的rollup() 函数的作用?
  12. TP6如何配置多应用?
  13. 清华计算机自主招生试题,2017年清华大学自主招生笔试真题及答案汇总|2017自主招生笔试真题(清华大学)|清华大学2017年自主招生笔试真题...
  14. 2022年全球市场柠檬酸单镁总体规模、主要生产商、主要地区、产品和应用细分研究报告
  15. C语言-5月23日-指针(一)
  16. 走进梦龙冰淇淋的生产线 揭晓“灯塔工厂”背后的秘密
  17. 移动WEB学习 - 字体图标、平面转换、渐变
  18. Dockerfile构建镜像并发布镜像
  19. 工具栏的打印图标不见了_电脑工具栏图标不见了怎么办啊
  20. 如何解决卸载McAfee时出现“处于托管模式时无法删除”问题

热门文章

  1. Python_面向对象_递归
  2. Java学习正嗨Day2!
  3. 视频监控线缆选型须知 转
  4. 详细介绍如何在win7下首次实现通过Git bash向Github提交项目
  5. android:由URL载入中ImageView
  6. Eclipse中JRE System Library、Web App Libraries的作用
  7. 饼状图改变数据显示位置_这么用MatPlotLib视觉化呈现数据,你值得拥有
  8. php ajax loading图片居中显示,ajax+php上次图片
  9. 视觉编码(Visual Encoding)
  10. luogu1991 无线通讯网