简介

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

#服务端

importsocketimportselect

s=socket.socket()

s.bind(('127.0.0.1',8888))

s.listen(5)

r_list=[s,]

num=0whileTrue:

rl, wl, error= select.select(r_list,[],[],10)

num+=1

print('counts is %s'%num)print("rl's length is %s"%len(rl))for fd inrl: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())exceptConnectionAbortedError:

r_list.remove(fd)

s.close()

#客户端

importsocket

flag= 1s=socket.socket()

s.connect(('127.0.0.1',8888))whileflag:

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个文件描述符

epoll方法

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

Trueif the epoll object isclosed.检测epoll对象是否关闭

epoll.fileno()

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

epoll.fromfd(fd)

Create an epoll objectfroma 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 descriptorfromthe epoll object.取消注册

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

Waitfor 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实例

#服务端

importsocketimportselect

s=socket.socket()

s.bind(('127.0.0.1',8888))

s.listen(5)

epoll_obj=select.epoll()

epoll_obj.register(s,select.EPOLLIN)

connections={}whileTrue:

events=epoll_obj.poll()for fd, event inevents:print(fd,event)if fd ==s.fileno():

conn, addr=s.accept()

connections[conn.fileno()]=conn

epoll_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())exceptBrokenPipeError:

epoll_obj.unregister(fd)

connections[fd].close()delconnections[fd]

s.close()

epoll_obj.close()

#客户端

importsocket

flag= 1s=socket.socket()

s.connect(('127.0.0.1',8888))whileflag:

input_msg= input('input>>>')if input_msg == '0':breaks.sendall(input_msg.encode())

msg= s.recv(1024)print(msg.decode())

s.close()

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

  1. python iterable对象_如何理解Python中的iterable对象

    转载请注明出处:https://www.jianshu.com/u/5e6f798c903a [^*] 表示注脚,在文末可以查看对应连接,但简书不支持该语法. 首先,容器和 iterable 间没有必 ...

  2. python参数传递方法_深入理解python中函数传递参数是值传递还是引用传递

    python 的 深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是&q ...

  3. python语句解释_深入理解python with 语句

    深入理解python with 语句 python中with 语句作为try/finally 编码范式的一种替代, 适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的" ...

  4. python赋值语句对错_深入理解Python中变量赋值的问题

    前言 在Python中变量名规则与其他大多数高级语言一样,都是受C语言影响的,另外变量名是大小写敏感的. Python是动态类型语言,也就是说不需要预先声明变量类型,变量的类型和值在赋值那一刻被初始化 ...

  5. python ioc框架_轻松理解 Spring 中的 IOC

    Spring 简介 Spring 是一个开源的轻量级的企业级框架,其核心是反转控制 (IoC) 和面向切面 (AOP) 的容器框架.我们可以把 Spring 看成是对象的容器,容器中可以包含很多对象, ...

  6. 深入理解python异步编程_深入理解Python异步编程

    1 什么是异步编程 1.1 阻塞程序未得到所需计算资源时被挂起的状态. 程序在等待某个操作完成期间,自身无法继续干别的事情,则称该程序在该操作上是阻塞的. 常见的阻塞形式有:网络I/O阻塞.磁盘I/O ...

  7. 完全理解python迭代对象_完全理解Python迭代对象、迭代器、生成器

    1.assert:python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假.可以理解assert断言语句为raise-if-not,用来测试表示式,其返回值为假,就会触 ...

  8. python怎么装饰_如何理解python装饰器

    如何理解装饰器 python 学习遇到的第一个难点是装饰器.装饰器的作用是不大规模改动代码的情况下,增加功能. 作用:为已经存在的对象添加额外的功能 特点:不需要对对象做任何的代码上的变动. 以一个例 ...

  9. 什么是python装饰器_深入理解 Python 装饰器

    作者简介 曾凡伟,携程信息安全部高级安全工程师,2015年加入携程,主要负责安全自动化产品的设计和研发,包括各类扫描器.漏洞管理平台.安全 SaaS 平台等. Python 是一门追求优雅编程的语言, ...

最新文章

  1. kalilinux安装VMware Tools(水文)
  2. 10.2 运算符重载函数作为类成员函数和友元函数
  3. TCP相关的面试内容整理
  4. 实测实量数据表格_建筑工程质量实测实量操作手册,130页PPT下载!
  5. linux设备驱动模块引用和依赖
  6. python判断今天周几_Python如何根据日期判断周几
  7. Java网络编程-1
  8. Angular环境配置及创建新的项目
  9. 你的SQL语句放在了哪里?
  10. echarts地图省市坐标
  11. 六维空间等IPV6资源上不去的一种解决方法
  12. c语言程序设计操作,c语言编程入门相关详细操作
  13. Selenium WebDriver 常用API
  14. u盘启动pe一键装机的步骤教程,u盘如何安装系统
  15. 乐安全 支持x86_不用苦等五一 四款近期主打平板推荐
  16. 信息论 | 计算离散信源的信息量和熵的MATLAB实现(函数封装调用)
  17. 关于C++中的一些特殊函数inline,virtual等等
  18. (附源码)springboot大学毕业设计管理系统 毕业设计030945
  19. wps中图片怎么居中_wps2010里插入图片如何使图片居中啊!
  20. 工业消防信息接入Java

热门文章

  1. Leetcode 236.二叉树的最近公共祖先
  2. 磁盘启动次数计算原理总结
  3. python numpy中bool变量转为1或0
  4. iOS 9检测QQ、微信是否安装
  5. ipv6 ripng配置
  6. MySql 建表出现的问题:[ERR] 1064 - You have an error in your SQL syntax; check the manual..........
  7. Eclipse Debug 配置
  8. jsp内置对象(三)-----response对象
  9. 第五篇:你“ 看不见 ” 的隐式转换
  10. 使用data attributes