Python中使用asyncio 封装文件读写


Posted in Python onSeptember 11, 2016

前言

和网络 IO 一样,文件读写同样是一个费事的操作。

默认情况下,Python 使用的是系统的阻塞读写。这意味着在 asyncio 中如果调用了

f = file('xx')
f.read()

会阻塞事件循环。

本篇简述如何用 asyncio.Future 对象来封装文件的异步读写。

代码在 GitHub。目前仅支持 Linux。

阻塞和非阻塞

首先需要将文件的读写改为非阻塞的形式。在非阻塞情况下,每次调用 read 都会立即返回,如果返回值为空,则意味着文件操作还未完成,反之则是读取的文件内容。

阻塞和非阻塞的切换与操作系统有关,所以本篇暂时只写了 Linux 版本。如果有过 Unix 系统编程经验,会发现 Python 的操作是类似的。

flag = fcntl.fcntl(self.fd, fcntl.F_GETFL) 
if fcntl.fcntl(self.fd, fcntl.F_SETFL, flag | os.O_NONBLOCK) != 0: 
  raise OSError()

Future 对象

Future 对象类似 Javascript 中的 Promise 对象。它是一个占位符,其值会在将来被计算出来。我们可以使用

result = await future

在 future 得到值之后返回。而使用

future.set_result(xxx)

就可以设置 future 的值,也意味着 future 可以被返回了。await 操作符会自动调用 future.result() 来得到值。

loop.call_soon

通过 loop.call_soon 方法可以将一个函数插入到事件循环中。

至此,我们的异步文件读写思路也就出来了。通过 loop.call_soon 调用非阻塞读写文件的函数。若一次文件读写没有完成,则计算剩余所学读写的字节数,并再次插入事件循环直至读写完毕。

可以发现其就是把传统 Unix 编程里,非阻塞文件读写的 while 循环换成了 asyncio 的事件循环。

下面是这一过程的示意代码。

def read_step(self, future, n, total):
  res = self.fd.read(n)
  if res is None:
    self.loop.call_soon(self.read_step, future, n, total)
    return
  if not res: # EOF
    future.set_result(bytes(self.rbuffer))
    return
  self.rbuffer.extend(res)
  self.loop.call_soon(self.read_step, future, self.BLOCK_SIZE, total)

def read(self, n=-1):
  future = asyncio.Future(loop=self.loop)

  self.rbuffer.clear()
  self.loop.call_soon(self.read_step, future, min(self.BLOCK_SIZE, n), n)

  return future
Python 相关文章推荐
Python简单读取json文件功能示例
Nov 30 Python
Python排序搜索基本算法之冒泡排序实例分析
Dec 09 Python
Python Selenium Cookie 绕过验证码实现登录示例代码
Apr 10 Python
Python列表解析配合if else的方法
Jun 23 Python
python数据结构之线性表的顺序存储结构
Sep 28 Python
实例讲解Python中整数的最大值输出
Mar 17 Python
python实现可逆简单的加密算法
Mar 22 Python
Django实现文件上传下载
Oct 06 Python
Python figure参数及subplot子图绘制代码
Apr 18 Python
Java ExcutorService优雅关闭方式解析
May 30 Python
Python类成员继承重写的实现
Sep 16 Python
Python操作word文档插入图片和表格的实例演示
Oct 25 Python
Python 如何访问外围作用域中的变量
Sep 11 #Python
Python优化技巧之利用ctypes提高执行速度
Sep 11 #Python
Python 中的with关键字使用详解
Sep 11 #Python
Python冒泡排序注意要点实例详解
Sep 09 #Python
通过5个知识点轻松搞定Python的作用域
Sep 09 #Python
python验证码识别的实例详解
Sep 09 #Python
Python随机数random模块使用指南
Sep 09 #Python
You might like
php实现ping
2006/10/09 PHP
php设计模式 Decorator(装饰模式)
2011/06/26 PHP
详解PHP对数组的定义以及数组的创建方法
2015/11/27 PHP
PHP实现的pdo连接数据库并插入数据功能简单示例
2019/03/30 PHP
php + ajax 实现的写入数据库操作简单示例
2020/05/16 PHP
js下判断 iframe 是否加载完成的完美方法
2010/10/26 Javascript
Jquery之美中不足小结
2011/02/16 Javascript
ExtJs设置GridPanel表格文本垂直居中示例
2013/07/15 Javascript
jquery检测input checked 控件是否被选中的方法
2014/03/26 Javascript
node.js中的socket.io的广播消息
2014/12/15 Javascript
jquery的ajax提交form表单的两种方法小结(推荐)
2016/05/25 Javascript
JavaScript中实现键值对应的字典与哈希表结构的示例
2016/06/12 Javascript
基于AngularJS实现iOS8自带的计算器
2016/09/12 Javascript
js实现文字跑马灯效果
2017/02/23 Javascript
async/await与promise(nodejs中的异步操作问题)
2017/03/03 NodeJs
Angularjs cookie 操作实例详解
2017/09/27 Javascript
Vue代码整洁之去重方法整理
2019/08/06 Javascript
JavaScript函数重载操作实例浅析
2020/05/02 Javascript
VSCode 添加自定义注释的方法(附带红色警戒经典注释风格)
2020/08/27 Javascript
element中table高度自适应的实现
2020/10/21 Javascript
原生JavaScript实现五子棋游戏
2020/11/09 Javascript
从零学python系列之数据处理编程实例(一)
2014/05/22 Python
详解Python爬虫的基本写法
2016/01/08 Python
django 修改server端口号的方法
2018/05/14 Python
python让列表倒序输出的实例
2018/06/25 Python
Django 路由控制的实现
2019/07/17 Python
Python request操作步骤及代码实例
2020/04/13 Python
html5的pushstate以及监听浏览器返回事件的实现
2020/08/11 HTML / CSS
传播学毕业生求职信
2013/10/11 职场文书
教师个人总结范文
2015/02/11 职场文书
物业工程部主管岗位职责
2015/04/16 职场文书
初中教务主任竞聘演讲稿(范文)
2019/08/20 职场文书
Python list去重且保持原顺序不变的方法
2021/04/03 Python
Mysql 性能监控及调优
2021/04/06 MySQL
Python Pandas pandas.read_sql函数实例用法
2021/06/21 Python
frg-100简单操作(设置)说明
2022/04/05 无线电