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实现定时同步本机与北京时间的方法
Mar 24 Python
Python的time模块中的常用方法整理
Jun 18 Python
Python字符串匹配算法KMP实例
Jul 18 Python
不同版本中Python matplotlib.pyplot.draw()界面绘制异常问题的解决
Sep 24 Python
python 简单备份文件脚本v1.0的实例
Nov 06 Python
python线程join方法原理解析
Feb 11 Python
Python sql注入 过滤字符串的非法字符实例
Apr 03 Python
PyQt5 文本输入框自动补全QLineEdit的实现示例
May 13 Python
Django项目在pycharm新建的步骤方法
Mar 02 Python
Django项目如何正确配置日志(logging)
Apr 29 Python
PyQt5结合QtDesigner实现文本框读写操作
Jun 11 Python
Python基础 括号()[]{}的详解
Nov 07 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
discuz7 phpMysql操作类
2009/06/21 PHP
php插入含有特殊符号数据的处理方法
2016/11/24 PHP
PHP的RSA加密解密方法以及开发接口使用
2018/02/11 PHP
javascript KeyDown、KeyPress和KeyUp事件的区别与联系
2009/12/03 Javascript
让textarea自动调整大小的js代码
2011/04/12 Javascript
JavaScript实现将UPC转换成ISBN的方法
2015/05/26 Javascript
Perl Substr()函数及函数的应用
2015/12/16 Javascript
js父页面中使用子页面的方法
2016/01/09 Javascript
JavaScript通过代码调用Flash显示的方法
2016/02/02 Javascript
终于实现了!精彩的jquery弹幕效果
2016/07/18 Javascript
jquery中用函数来设置css样式
2016/12/22 Javascript
vue获取元素宽、高、距离左边距离,右,上距离等还有XY坐标轴的方法
2018/09/05 Javascript
vue中使用input[type="file"]实现文件上传功能
2018/09/10 Javascript
JS面试题大坑之隐式类型转换实例代码
2018/10/14 Javascript
Layui实现带查询条件的分页
2019/07/27 Javascript
javascript实现鼠标点击生成文字特效
2019/12/24 Javascript
在Vue中实现随hash改变响应菜单高亮
2020/03/09 Javascript
js实现简单五子棋游戏
2020/05/28 Javascript
python插入排序算法实例分析
2015/07/03 Python
Django小白教程之Django用户注册与登录
2016/04/22 Python
教你如何编写、保存与运行Python程序的方法
2019/07/12 Python
Flask配置Cors跨域的实现
2019/07/12 Python
python3+openCV 获取图片中文本区域的最小外接矩形实例
2020/06/02 Python
python3 简单实现组合设计模式
2020/07/02 Python
pycharm中如何自定义设置通过“ctrl+滚轮”进行放大和缩小实现方法
2020/09/16 Python
美国第二大团购网站:LivingSocial
2016/07/24 全球购物
可打印的优惠券、杂货和优惠券代码:Coupons.com
2018/06/12 全球购物
乡镇纠风工作实施方案
2014/03/22 职场文书
预备党员公开承诺书
2014/05/28 职场文书
警察群众路线对照检查材料思想汇报
2014/10/01 职场文书
导游词之崇武古城
2019/10/07 职场文书
你离财务总监还有多远?速览CFO的岗位职责
2019/11/18 职场文书
Python 中的单分派泛函数你真的了解吗
2021/06/22 Python
HTML中的表单元素介绍
2022/02/28 HTML / CSS
Python捕获、播放和保存摄像头视频并提高视频清晰度和对比度
2022/04/14 Python
SQL试题 使用窗口函数选出连续3天登录的用户
2022/04/24 Oracle