Python 高级 I/O 多路复用
Table of Contents
前言
第一次接触和 I/O 多路复用相关的概念是在书 CSAPP1 的并发编程章节,当时在了解了这个概念后只是感觉很神奇,但是并没有实际使用过。
直到接触了和 异步 I/O 相关的概念,然后才发现,并发和 I/O 这一块的东西还真的有点多。
这篇博客的内容算是对 I/O 多路复用的简单介绍以及和 selectors 模块的简单使用。
select
介绍 I/O 多路复用这个概念往往都是从 select 这个 系统调用 开始的,这篇博客也不例外,但是为了方便,我们使用的是 Python 提供的 select.select 函数2。
这个函数的参数列表与返回值是这样的:
select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)
各个参数的含义:
rlist- 等待 可读 事件发生的文件描述符列表wlist- 等待 可写 事件发生的文件描述符列表xlist- 等待 异常 事件发生的文件描述符列表timeout- 可选,指定最长阻塞等待时间
调用这个函数后会 阻塞 等待和各个的文件描述符相对应的 I/O 事件发生,然后将准备好的文件描述符返回。
I/O 多路复用的基本模型就和这个函数一样,都是通过一定的方式监听处理 多个 文件的 I/O 事件,或者说,select 是 I/O 多路复用的一种实现。
除了 select 以外,常见的还有 poll 和 epoll 这两个实现,它们背后的基本思想都是一样的,区别主要就在于使用的方便性和效率上。
selectors
selectors 模块是对 select 的一层封装,能够让我们以更方便的方式来使用 I/O 多路复用。
简单的使用流程为:
通过
selectors.DefaultSelector()创建默认的selector当然还存在其他不同种类的
Selector, 但是不同种类的Selector的受支持情况在不同的平台上存在差异,因此大多数时候使用DefaultSelector就可以了,它是相应平台上最有效的Selector的易名。通过
selector.register(fileobj, events, data=None)方法注册需要监听的 文件描述符 或 文件对象可以看到,在使用
selector时我们可以注册 文件对象 而不一定必须要是 文件描述符3,这为我们的使用带来了一定的便利。对于参数
events, 在selectors模块中定义的事件只有EVENT_READ和EVENT_WRITE, 刨除了不太常用的 异常 事件。如果要同时注册两个事件可以像这样:
selector.register(fileobj, EVENT_READ | EVENT_WRITE)
调用
selector.select(timeout=None)方法监听并获取发生了的 键 - 事件 对列表这里的键是指
SelectorKey对象,它的属性包括:fileobj- 我们注册的文件对象fd- 我们注册的文件对象的文件描述符events- 我们注册的事件data- 注册时的data参数
处理得到的 键 - 事件 对列表
如果注册了不同类型的事件,处理时可以通过返回的事件类型进行处理。
同时,我们可以在注册时通过
data参数附带回调函数,方便处理。
下面是官网的例子:
import selectors
import socket
sel = selectors.DefaultSelector()
def accept(sock, mask):
conn, addr = sock.accept() # Should be ready
print('accepted', conn, 'from', addr)
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read)
def read(conn, mask):
data = conn.recv(1000) # Should be ready
if data:
print('echoing', repr(data), 'to', conn)
conn.send(data) # Hope it won't block
else:
print('closing', conn)
sel.unregister(conn)
conn.close()
sock = socket.socket()
sock.bind(('localhost', 1234))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
结语
虽然接触 I/O 多路复用已经有一段时间了,但是还没有遇到过需要使用的地方……
或者说需要使用的地方已经被相关类库的作者封装好了,没自己什么事了 @_@
但是,掌握相关的概念还是很有价值的。
参考链接
- selectors — High-level I/O multiplexing — Python 3.7.3 documentation
- cpython/selectors.py at 3.7 · python/cpython
Footnotes
1 Computer Systems: A Programmer's Perspective, 3/E (CS:APP3e)
2 C 语言版可以参考 select - Wikipedia
3 文件描述符可以通过文件对象的 fileno() 方法获取
Python 高级 I/O 多路复用的更多相关文章
- python高级之网络编程
python高级之网络编程 本节内容 网络通信概念 socket编程 socket模块一些方法 聊天socket实现 远程执行命令及上传文件 socketserver及其源码分析 1.网络通信概念 说 ...
- 第六篇:python高级之网络编程
python高级之网络编程 python高级之网络编程 本节内容 网络通信概念 socket编程 socket模块一些方法 聊天socket实现 远程执行命令及上传文件 socketserver及 ...
- 老男孩Python高级全栈开发工程师【真正的全套完整无加密】
点击了解更多Python课程>>> 老男孩Python高级全栈开发工程师[真正的全套完整无加密] 课程大纲 老男孩python全栈,Python 全栈,Python教程,Django ...
- 第十一章:Python高级编程-协程和异步IO
第十一章:Python高级编程-协程和异步IO Python3高级核心技术97讲 笔记 目录 第十一章:Python高级编程-协程和异步IO 11.1 并发.并行.同步.异步.阻塞.非阻塞 11.2 ...
- python 高级之面向对象初级
python 高级之面向对象初级 本节内容 类的创建 类的构造方法 面向对象之封装 面向对象之继承 面向对象之多态 面向对象之成员 property 1.类的创建 面向对象:对函数进行分类和封装,让开 ...
- python高级之函数
python高级之函数 本节内容 函数的介绍 函数的创建 函数参数及返回值 LEGB作用域 特殊函数 函数式编程 1.函数的介绍 为什么要有函数?因为在平时写代码时,如果没有函数的话,那么将会出现很多 ...
- python高级之装饰器
python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函数的定义: 满足下面两个条件之 ...
- python高级之生成器&迭代器
python高级之生成器&迭代器 本机内容 概念梳理 容器 可迭代对象 迭代器 for循环内部实现 生成器 1.概念梳理 容器(container):多个元素组织在一起的数据结构 可迭代对象( ...
- python高级之面向对象高级
python高级之面向对象高级 本节内容 成员修饰符 特殊成员 类与对象 异常处理 反射/自省 单例模式 1.成员修饰符 python的类中只有私有成员和公有成员两种,不像c++中的类有公有成员(pu ...
随机推荐
- 写给future的话
学习任何事务,永远不要被繁复的表象所迷惑. 觉得自己知识不够深,了解的不够多,其实就是思考感悟的不够罢了. 想,都是问题,做,才有答案 换位思考是人际交往最重要的能力之一.
- MySQL 相关文章参考
MySQL 中隔离级别 RC 与 RR 的区别http://www.cnblogs.com/digdeep/p/4968453.html MySQL+InnoDB semi-consitent rea ...
- Java解析html页面,获取想要的元素
背景:通过接口访问数据,获取的内容是个标准的html格式,使用jsoup的方式获取页面元素值 先推荐比较好的博客:http://www.open-open.com/jsoup/. 单个案例比较不错 h ...
- 图像上采样(图像插值)增取样(Upsampling)或内插(Interpolating)下采样(降采样),
缩小图像(或称为下采样(subsampled)或降采样(downsampled))的主要目的有两个:1.使得图像符合显示区域的大小:2.生成对应图像的缩略图.放大图像(或称为上采样(upsamplin ...
- Eclipse Python插件 PyDev
PyDev for Eclipse 是一个功能强大且易用的 Eclipse Python IDE 插件.本文将向读者介绍 PyDev 开源项目及其安装配置方法,并在此基础上详细介绍如何利用 PyDev ...
- 使用免费公开的api接口示例(iOS)
做项目难免需要测试,要测试就需要一些接口,现在网上的很多接口都是需要收费的. 以下是目前找到的免费 JSON API免费接口 云聚数据 网吧数据 其中选取了一个百度百科的接口 百度接口 百度百科接口: ...
- CocoaAsyncSocket使用
代理的.h文件 #import <Foundation/Foundation.h> #import "GCDAsyncSocket.h" typedef void(^S ...
- java对一个int数组进行排序、去重
思路: 1.使用 HashSet 进行去重 2.将 HashSet 变为 TreeSet 3.使用 TreeSet 进行排序 4.将 Set 变为 Integer 数组 5.将 Integer 数组变 ...
- C#进阶学习笔记(个人整理)
学习笔记 第一章: 一.回顾数组 1.变量 : 只能存储一个数据 2.数组 :存储固定大小的相同类型的数据 3.对象 : 存储多个相同/不同类型的数据 4.集合 : 特殊的容器,存储N个相同/不同类型 ...
- Pagehelper介绍
本文引自:https://my.oschina.net/zudajun/blog/745232 摘要: com.github.pagehelper.PageHelper是一款好用的开源免费的Mybat ...