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中使用Tkinter模块创建GUI程序实例
Jan 14 Python
Windows8下安装Python的BeautifulSoup
Jan 22 Python
Python快速从注释生成文档的方法
Dec 26 Python
python算法表示概念扫盲教程
Apr 13 Python
Python3结合Dlib实现人脸识别和剪切
Jan 24 Python
对pandas通过索引提取dataframe的行方法详解
Feb 01 Python
python 使用turtule绘制递归图形(螺旋、二叉树、谢尔宾斯基三角形)
May 30 Python
pandas计数 value_counts()的使用
Jun 24 Python
Flask框架模板继承实现方法分析
Jul 31 Python
pycharm快捷键汇总
Feb 14 Python
python通用读取vcf文件的类(复制粘贴即可用)
Feb 29 Python
python爬虫用request库处理cookie的实例讲解
Feb 20 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&mysql(六)
2006/10/09 PHP
PHP 字符串操作入门教程
2006/12/06 PHP
php stream_get_meta_data返回值
2013/09/29 PHP
Laravel 5框架学习之用户认证
2015/04/09 PHP
PHP使用pdo连接access数据库并循环显示数据操作示例
2018/06/05 PHP
php微信分享到朋友圈、QQ、朋友、微博
2019/02/18 PHP
PHP 结合 Boostrap 结合 js 实现学生列表删除编辑及搜索功能
2019/05/21 PHP
JavaScript高级程序设计(第3版)学习笔记 概述
2012/10/11 Javascript
利用js读取动态网站从服务器端返回的数据
2014/02/10 Javascript
bootstrap——bootstrapTable实现隐藏列的示例
2017/01/14 Javascript
利用Node.js编写跨平台的spawn语句详解
2017/02/12 Javascript
node.js平台下利用cookie实现记住密码登陆(Express+Ejs+Mysql)
2017/04/26 Javascript
ES6学习教程之对象的扩展详解
2017/05/02 Javascript
JS中利用swiper实现3d翻转幻灯片实例代码
2017/08/25 Javascript
ES6基础之字符串和函数的拓展详解
2019/08/22 Javascript
[05:04]DOTA2上海特级锦标赛主赛事第二日TOP10
2016/03/04 DOTA
python fabric实现远程操作和部署示例
2014/03/25 Python
使用Python的Treq on Twisted来进行HTTP压力测试
2015/04/16 Python
Python脚本获取操作系统版本信息
2016/12/17 Python
TensorFlow实现Logistic回归
2018/09/07 Python
Python单元和文档测试实例详解
2019/04/11 Python
Django 权限认证(根据不同的用户,设置不同的显示和访问权限)
2019/07/24 Python
pytorch中的embedding词向量的使用方法
2019/08/18 Python
使用matplotlib绘制图例标签中带有公式的图
2019/12/13 Python
Python使用monkey.patch_all()解决协程阻塞问题
2020/04/15 Python
基于tensorflow for循环 while循环案例
2020/06/30 Python
eDreams巴西:廉价机票,酒店优惠和度假套餐
2017/04/14 全球购物
高中物理教学反思
2014/02/08 职场文书
区优秀教师事迹材料
2014/02/10 职场文书
总经理助理的职责
2014/03/14 职场文书
大学新闻系自荐书
2014/05/31 职场文书
2014年大学生职业规划书:未来不是梦,只要勇敢冲!
2014/09/22 职场文书
2015年安全生产目标责任书
2015/01/29 职场文书
朝花夕拾读书笔记
2015/06/29 职场文书
2015年音乐教研组工作总结
2015/07/22 职场文书
24句精辟的现实社会语录,句句扎心,道尽人性
2019/08/29 职场文书