Table of Contents

  1. 前言
  2. select
  3. selectors
  4. 结语
  5. 参考链接

前言

第一次接触和 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 以外,常见的还有 pollepoll 这两个实现,它们背后的基本思想都是一样的,区别主要就在于使用的方便性和效率上。

selectors

selectors 模块是对 select 的一层封装,能够让我们以更方便的方式来使用 I/O 多路复用。

简单的使用流程为:

  1. 通过 selectors.DefaultSelector() 创建默认的 selector

    当然还存在其他不同种类的 Selector, 但是不同种类的 Selector 的受支持情况在不同的平台上存在差异,因此大多数时候使用 DefaultSelector 就可以了,它是相应平台上最有效的 Selector 的易名。

  2. 通过 selector.register(fileobj, events, data=None) 方法注册需要监听的 文件描述符文件对象

    可以看到,在使用 selector 时我们可以注册 文件对象 而不一定必须要是 文件描述符3,这为我们的使用带来了一定的便利。

    对于参数 events, 在 selectors 模块中定义的事件只有 EVENT_READEVENT_WRITE, 刨除了不太常用的 异常 事件。

    如果要同时注册两个事件可以像这样:

    selector.register(fileobj, EVENT_READ | EVENT_WRITE)
  3. 调用 selector.select(timeout=None) 方法监听并获取发生了的 键 - 事件 对列表

    这里的键是指 SelectorKey 对象,它的属性包括:

    • fileobj - 我们注册的文件对象
    • fd - 我们注册的文件对象的文件描述符
    • events - 我们注册的事件
    • data - 注册时的 data 参数
  4. 处理得到的 键 - 事件 对列表

    如果注册了不同类型的事件,处理时可以通过返回的事件类型进行处理。

    同时,我们可以在注册时通过 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 多路复用已经有一段时间了,但是还没有遇到过需要使用的地方……

或者说需要使用的地方已经被相关类库的作者封装好了,没自己什么事了 @_@

但是,掌握相关的概念还是很有价值的。

参考链接

Footnotes

1 Computer Systems: A Programmer's Perspective, 3/E (CS:APP3e)

2 C 语言版可以参考 select - Wikipedia

3 文件描述符可以通过文件对象的 fileno() 方法获取

Python 高级 I/O 多路复用的更多相关文章

  1. python高级之网络编程

    python高级之网络编程 本节内容 网络通信概念 socket编程 socket模块一些方法 聊天socket实现 远程执行命令及上传文件 socketserver及其源码分析 1.网络通信概念 说 ...

  2. 第六篇:python高级之网络编程

    python高级之网络编程   python高级之网络编程 本节内容 网络通信概念 socket编程 socket模块一些方法 聊天socket实现 远程执行命令及上传文件 socketserver及 ...

  3. 老男孩Python高级全栈开发工程师【真正的全套完整无加密】

    点击了解更多Python课程>>> 老男孩Python高级全栈开发工程师[真正的全套完整无加密] 课程大纲 老男孩python全栈,Python 全栈,Python教程,Django ...

  4. 第十一章:Python高级编程-协程和异步IO

    第十一章:Python高级编程-协程和异步IO Python3高级核心技术97讲 笔记 目录 第十一章:Python高级编程-协程和异步IO 11.1 并发.并行.同步.异步.阻塞.非阻塞 11.2 ...

  5. python 高级之面向对象初级

    python 高级之面向对象初级 本节内容 类的创建 类的构造方法 面向对象之封装 面向对象之继承 面向对象之多态 面向对象之成员 property 1.类的创建 面向对象:对函数进行分类和封装,让开 ...

  6. python高级之函数

    python高级之函数 本节内容 函数的介绍 函数的创建 函数参数及返回值 LEGB作用域 特殊函数 函数式编程 1.函数的介绍 为什么要有函数?因为在平时写代码时,如果没有函数的话,那么将会出现很多 ...

  7. python高级之装饰器

    python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函数的定义: 满足下面两个条件之 ...

  8. python高级之生成器&迭代器

    python高级之生成器&迭代器 本机内容 概念梳理 容器 可迭代对象 迭代器 for循环内部实现 生成器 1.概念梳理 容器(container):多个元素组织在一起的数据结构 可迭代对象( ...

  9. python高级之面向对象高级

    python高级之面向对象高级 本节内容 成员修饰符 特殊成员 类与对象 异常处理 反射/自省 单例模式 1.成员修饰符 python的类中只有私有成员和公有成员两种,不像c++中的类有公有成员(pu ...

随机推荐

  1. POJ - 3470 Walls

    小鸟往四个方向飞都枚举一下,数据范围没给,离散以后按在其中一个轴线排序,在线段树上更新墙的id,然后就是点查询在在哪个墙上了. 这题有个trick,因为数据范围没给我老以为是inf设置小了,WA了很多 ...

  2. 判断团队适不适合使用node

    1.要不要用 2.历史包袱 3.跟进升级 看完scott创业公司使用node,对于一个团队要不要使用node,第一个就是如果承接的项目有很多历史迭代,线上也在稳定的抛,不要轻易的替换,比如很多老代码, ...

  3. G711格式语音采集/编码/转码/解码/播放

    2019-05-01 语音g711格式和AMR格式类似,应用很简单,很多人已经整理过了,收录于此,以备不时之需,用别人现成的足矣,我们的时间应该用来干更有意义的事. 1.PCM to G711 Fas ...

  4. 2017.10.27 C语言精品集

    第一章 程序设计和C语言 1.1 什么是计算机程序? @ ······ 所谓程序,就是一组计算机能识别和执行的指令.每一条指令使计算机执行特定的操作. 计算机的一切操作都是由程序控制的.所以计算机的本 ...

  5. GAN的调研和学习

    近期集中学习了GAN,下面记录一下调研的结果,和学习的心得,疏漏的地方,敬请指正. 本文将分为几个部分进行介绍,首先是GAN的由来,其次是GAN的发展,最后是GAN的应用. 先把最近收集的资料列举一下 ...

  6. IOS开发中缓存策略

    为了节约流量,同时也是为了更好的用户体验,目前很多应用都使用本地缓存机制,其中以网易新闻的缓存功能最为出色.我自己的应用也想加入本地缓存的功能,于是我从网上查阅了相关的资料,发现总体上说有两种方法.一 ...

  7. ZJOI2019Round#2

    乱听课记录 关于树的分治问题&杂题选讲 张哲宇 边分治 (边分不是很鸡肋吗) 例题一 题目大意:给出两颗有正负边权的树,求出两个点\(u,v​\)使得两棵树中\((u,v)​\)距离的和最大. ...

  8. GUI测试问题汇总

    1.ajax实现的页面元素定位问题 最近在做项目的时候遇到一个问题,通过xpath定位到元素后做一个循环操作,第一循环可以正常执行,第二次循环后就报错,错误信息:Message: The elemen ...

  9. 面试题 LazyMan 的Rxjs实现方式

    前言 笔者昨天在做某公司的线上笔试题的时候遇到了最后一道关于如何实现LazyMan的试题,题目如下 实现一个LazyMan,可以按照以下方式调用:LazyMan("Hank")输出 ...

  10. (转)基于REST架构的Web Service设计

    原文出处:http://www.williamlong.info/archives/1728.html ------------------------------------------------ ...