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封装对象实现时间效果
Apr 23 Python
wxPython事件驱动实例详解
Sep 28 Python
python实现批量获取指定文件夹下的所有文件的厂商信息
Sep 28 Python
对Python中range()函数和list的比较
Apr 19 Python
Python实现随机取一个矩阵数组的某几行
Nov 26 Python
Python3列表List入门知识附实例
Feb 09 Python
python 给图像添加透明度(alpha通道)
Apr 09 Python
Python自定义聚合函数merge与transform区别详解
May 26 Python
Python并发请求下限制QPS(每秒查询率)的实现代码
Jun 05 Python
TensorFlow的环境配置与安装教程详解(win10+GeForce GTX1060+CUDA 9.0+cuDNN7.3+tensorflow-gpu 1.12.0+python3.5.5)
Jun 22 Python
pytorch VGG11识别cifar10数据集(训练+预测单张输入图片操作)
Jun 24 Python
Python开发工具Pycharm的安装以及使用步骤总结
Jun 24 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
开源SNS系统-ThinkSNS
2008/05/18 PHP
thinkphp 一个页面使用2次分页的实现方法
2013/07/15 PHP
PHP函数超时处理方法
2016/02/14 PHP
php字符串操作常见问题小结
2016/10/11 PHP
PHP实现数据库的增删查改功能及完整代码
2018/04/18 PHP
Laravel5.0+框架邮件发送功能实现方法图文与实例详解
2019/04/23 PHP
jQuery中的.bind()、.live()和.delegate()之间区别分析
2011/06/08 Javascript
微信内置浏览器私有接口WeixinJSBridge介绍
2015/05/25 Javascript
JavaScript常用函数工具集:lao-utils
2016/03/01 Javascript
Bootstrap中的Panel和Table全面解析
2016/06/13 Javascript
JavaScript在form表单中使用button按钮实现submit提交方法
2017/01/23 Javascript
Javascript下拉刷新的简单实现
2017/02/14 Javascript
原生JS实现层叠轮播图
2017/05/17 Javascript
Node.Js中实现端口重用原理详解
2018/05/03 Javascript
Python爬虫中urllib库的进阶学习
2018/01/05 Python
详解CSS3 弹性布局快速入门
2019/06/06 HTML / CSS
HTML5 video 视频标签使用介绍
2014/02/03 HTML / CSS
美国内衣品牌:Leonisa
2016/08/14 全球购物
全球摩托车装备领导者:RevZilla
2017/09/04 全球购物
全球速卖通:AliExpress(国际版淘宝)
2017/09/20 全球购物
绘画设计学生的个人自我评价
2013/09/20 职场文书
先进集体获奖感言
2014/02/13 职场文书
捐资助学倡议书
2014/04/15 职场文书
白岩松演讲
2014/05/21 职场文书
专项法律服务方案
2014/06/11 职场文书
元旦晚会活动总结
2014/07/09 职场文书
自我管理的活动方案
2014/08/25 职场文书
2015年党员个人自我评价
2015/03/03 职场文书
离婚案件原告代理词
2015/05/23 职场文书
思品教学工作总结
2015/08/10 职场文书
个人售房合同协议书
2016/03/21 职场文书
mysql知识点整理
2021/04/05 MySQL
MySQL入门命令之函数-单行函数-流程控制函数
2021/04/05 MySQL
Python3中最常用的5种线程锁实例总结
2021/07/07 Python
CSS实现两列布局的N种方法
2021/08/02 HTML / CSS
Log4j.properties配置及其使用
2021/08/02 Java/Android