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 命令行参数sys.argv
Sep 06 Python
Python爬虫番外篇之Cookie和Session详解
Dec 27 Python
python3实现跳一跳点击跳跃
Jan 08 Python
urllib和BeautifulSoup爬取维基百科的词条简单实例
Jan 17 Python
对python中raw_input()和input()的用法详解
Apr 22 Python
python实现读Excel写入.txt的方法
Apr 29 Python
python3模块smtplib实现发送邮件功能
May 22 Python
Jupyter中直接显示Matplotlib的图形方法
May 24 Python
Python可视化mhd格式和raw格式的医学图像并保存的方法
Jan 24 Python
python可视化爬虫界面之天气查询
Jul 03 Python
Python3内置模块random随机方法小结
Jul 13 Python
详解用selenium来下载小姐姐图片并保存
Jan 26 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中OO之静态关键字以及类常量的详解
2013/06/07 PHP
修改apache配置文件去除thinkphp url中的index.php
2014/01/17 PHP
javaScript中两个等于号和三个等于号之间的区别介绍
2014/06/27 Javascript
用jquery模仿的a的title属性的例子
2014/10/22 Javascript
在Javascript中处理数组之toSource()方法的使用
2015/06/09 Javascript
JS防止网页被嵌入iframe框架的方法分析
2016/09/13 Javascript
AngularJS指令中的绑定策略实例分析
2016/12/14 Javascript
angular.js+node.js实现下载图片处理详解
2017/03/31 Javascript
微信小程序实现顶部普通选项卡效果(非swiper)
2020/06/19 Javascript
vue.js绑定事件监听器示例【基于v-on事件绑定】
2018/07/07 Javascript
Vue2.0学习系列之项目上线的方法步骤(图文)
2018/09/25 Javascript
Vue CLI3 开启gzip压缩文件的方式
2018/09/30 Javascript
实例讲解JavaScript截取字符串
2018/11/30 Javascript
解决微信小程序中转换时间格式IOS不兼容的问题
2019/02/15 Javascript
js实现二级联动简单实例
2020/01/11 Javascript
Python设计模式之中介模式简单示例
2018/01/09 Python
Python实现的json文件读取及中文乱码显示问题解决方法
2018/08/06 Python
Python内置类型性能分析过程实例
2020/01/29 Python
信号生成及DFT的python实现方式
2020/02/25 Python
关于python中的xpath解析定位
2020/03/06 Python
详解pandas.DataFrame.plot() 画图函数
2020/06/14 Python
如何在VSCode下使用Jupyter的教程详解
2020/07/13 Python
pandas按条件筛选数据的实现
2021/02/20 Python
canvas仿写贝塞尔曲线的示例代码
2017/12/29 HTML / CSS
揠苗助长教学反思
2014/02/04 职场文书
《美丽的小兴安岭》教学反思
2014/02/26 职场文书
乔迁之喜主持词
2014/03/27 职场文书
环保建议书500字
2014/05/14 职场文书
党员干部一句话承诺
2014/05/30 职场文书
餐厅感恩节活动策划方案
2014/10/11 职场文书
运动会广播稿200字(10篇)
2014/10/12 职场文书
公司员工安全协议书
2014/11/21 职场文书
2015教师节通讯稿
2015/07/20 职场文书
高一作文之乐趣
2019/11/21 职场文书
python文件目录操作之os模块
2021/05/08 Python
深入理解python协程
2021/06/15 Python