asyncio之异步上下文管理器
异步上下文管理器
前面文章我们提到了上下文管理器,但是这个上下文管理器只适用于同步代码,不能用于异步代码(async def形式),不过不用担心今天我们就来讨论在异步中如何使用上下文管理器。
特别提醒本教程所使用的Python版本为Python3.7。
async with
异步上下文管理器。类似于同步上下文管理器,我们知道使用with可以实现一个上下文管理的器,而对于异步上下文管理器其根本表现形式为async with,下面的一段代码告诉你async with是如何运作的。
import asyncio
class AContext:
def __init__(self):
print("in init")
async def __aenter__(self):
print("in aenter")
async def __aexit__(self, exc_type, exc_val, exc_tb):
print("in aexit")
async def main():
async with AContext() as ac:
print("in with", ac)
if __name__ == '__main__':
print("start")
asyncio.run(main())
输出内容
start
in init
in aenter
in with None
in aexit
下面说下async with和with的不同地方
语法上,with实现了enter和exit两个方法,async with实现了类似方法
aenter和aexit在同步的基础上加个a,实际上就是代表asynchronous。
实现上,使用普通的函数就可以实现with,但是async with需要通过异步函数的形式去实现,就像上面的例子一样。
asynccontextmanager
从Python 3.7开始,有两种方法可以编写异步上下文管理器。一种就是前面提到的魔法函数的实现,另外一种就是contextlib的另外一个模块asynccontextmanager。通过装饰器的方式实现一个异步上下文管理器
import asyncio
from contextlib import asynccontextmanager
from concurrent.futures.thread import ThreadPoolExecutor
class AsyncFile(object):
def __init__(self, file, loop=None, executor=None):
if not loop:
loop = asyncio.get_running_loop() # 获取当前运行事件循环
if not executor:
executor = ThreadPoolExecutor(10) # 线程池数量10
self.file = file
self.loop = loop
self.executor = executor
self.pending = []
self.result = []
def write(self, string):
"""
实现异步写操作
:param string: 要写的内容
:return:
"""
self.pending.append(
self.loop.run_in_executor(
self.executor, self.file.write, string,
)
)
def read(self, i):
"""
实现异步读操作
:param i:
:return:
"""
self.pending.append(
self.loop.run_in_executor(self.executor, self.file.read, i,)
)
def readlines(self):
self.pending.append(
self.loop.run_in_executor(self.executor, self.file.readlines, )
)
@asynccontextmanager
async def async_open(path, mode="w"):
with open(path, mode=mode) as f:
loop = asyncio.get_running_loop()
file = AsyncFile(f, loop=loop)
try:
yield file
finally:
file.result = await asyncio.gather(*file.pending, loop=loop)
上面的代码通过使用asyncio中run_in_executor运行一个线程,来使得阻塞操作变为非阻塞操作,达到异步非阻塞的目的。
AsyncFile类提供了一些方法,这些方法将用于将write、read和readlines的调用添加到pending列表中。这些任务通过finally块中的事件循环在ThreadPoolExecutor进行调度。
yield 前半段用来表示_aenter_()
yield 后半段用来表示_aexit_()
使用finally以后可以保证链接资源等使用完之后能够关闭。
运行异步上下文管理器
如果调用前面示例中的异步上下文管理器,则需要使用关键字async with来进行调用。另外带有async with的语句只能在异步函数中使用。
from asynciodemo.asyncwith import async_open
import asyncio
import tempfile
import os
async def main():
tempdir = tempfile.gettempdir()
path = os.path.join(tempdir, "run.txt")
print(f"临时文件目录:{path}")
async with async_open(path, mode='w') as f:
f.write("公众号: ")
f.write("Python")
f.write("学习")
f.write("开发")
if __name__ == '__main__':
asyncio.run(main())
使用方法和with类似可以通过使用as,然后使用其句柄,唯一需要注意的就是要在异步函数中使用。
同步任务
在之前的一些异步教程里和大家说了关于协程中的几个同步方法,asyncio.wait和asyncio.gather,这里我们可以配合这些方法通过异步上下文管理器来实现同步任务,请看如下代码
import asyncio
# 同步挂起协程
class Sync():
def __init__(self):
self.pending = []
self.finished = None
def schedule_coro(self, coro, shield=True):
#如果去掉asyncio.shield,在取消fut函数的时候,就会导致coro协程也出错。
fut = asyncio.shield(coro) if shield else asyncio.ensure_future(coro)
self.pending.append(fut)
return fut
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
# 退出async with的时候,任务列表中的任务进行并发操作。
self.finished = await asyncio.gather(*self.pending, return_exceptions=True)
async def workload1():
await asyncio.sleep(2)
print("These coroutines will be executed return 41")
return 41
async def workload2():
await asyncio.sleep(2)
print("These coroutines will be executed return 42")
return 42
async def workload3():
await asyncio.sleep(2)
print("These coroutines will be executed return 43")
return 43
async def main():
async with Sync() as sync:
# 使用异步上下文可以创建同步协程程序
sync.schedule_coro(workload1())
sync.schedule_coro(workload2())
sync.schedule_coro(workload3())
print("All scheduled corotines have retuned or throw:", sync.finished)
if __name__ == '__main__':
asyncio.run(main())
输出
These coroutines will be executed return 41
These coroutines will be executed return 42
These coroutines will be executed return 43
All scheduled corotines have retuned or throw: [41, 42, 43]
1.程序是同步的形式并发输出的。
2. schedule_coro的作用是将协程workload1,workload2,workload3添加到任务列表pending,退出async with的时候,任务列表中的任务进行并发操作。
asyncio之异步上下文管理器的更多相关文章
- 深入Asyncio(七)异步上下文管理器
Async Context Managers: async with 在某些场景下(如管理网络资源的连接建立.断开),用支持异步的上下文管理器是很方便的. 那么如何理解async with关键字? 先 ...
- python 黑魔法 ---上下文管理器(contextor)
所谓上下文 计算机上下文(Context)对于我而言,一直是一个很抽象的名词.就像形而上一样,经常听见有人说,但是无法和现实认知世界相结合. 最直观的上下文,莫过于小学的语文课,经常会问联系上下文,推 ...
- (转)Python中的上下文管理器和Tornado对其的巧妙应用
原文:https://www.binss.me/blog/the-context-manager-of-python-and-the-applications-in-tornado/ 上下文是什么? ...
- Python 上下文管理器模块--contextlib
在 Python 处理文件的时候我们使用 with 关键词来进行文件的资源关闭,但是并不是只有文件操作才能使用 with 语句.今天就让我们一起学习 Python 中的上下文管理 contextlib ...
- Python 的上下文管理器是怎么设计的?
花下猫语:最近,我在看 Python 3.10 版本的更新内容时,发现有一个关于上下文管理器的小更新,然后,突然发现上下文管理器的设计 PEP 竟然还没人翻译过!于是,我断断续续花了两周时间,终于把这 ...
- python2.7高级编程 笔记一(Python中的with语句与上下文管理器学习总结)
0.关于上下文管理器上下文管理器是可以在with语句中使用,拥有__enter__和__exit__方法的对象. with manager as var: do_something(var) 相当于以 ...
- 翻译《Writing Idiomatic Python》(五):类、上下文管理器、生成器
原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...
- python学习笔记4(对象/引用;多范式; 上下文管理器)
### Python的强大很大一部分原因在于,它提供有很多已经写好的,可以现成用的对象 21. 动态类型:对象/引用 对象和引用: 对象是储存在内存中的实体,对象名只是指向这一对象的引用(refere ...
- Python深入02 上下文管理器
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 上下文管理器(context manager)是Python2.5开始支持的一种语 ...
随机推荐
- charles 的安装和手机配置 (我用的win7系统 ,和 iphone8 的配置)
2018/12/17 由于想抓一下某个手机上app的数据,然后就装了charles,纯记录一下,便于以后不用再查资料.个人参考的网址:https://blog.csdn.net/weixin_4233 ...
- JavaScript_day01
1.变量声明 怎么声明变量? JavaScript中变量声明用的关键字是 var 变量名称. 变量名称命名有什么限制? 变量名称命名需规范,准则:不能以数字开头,不能含有特殊字符(css的属性),可以 ...
- 谷歌浏览器调试手机app内置网页
当自己的H5项目内置于手机app内时,遇到了样式问题或者想查看H5页面代码.数据交互以及缓存等情况来检查数据,此时可以使用谷歌浏览器的控制台远程调试手机,步骤如下: 一.手机开启允许usb调试 二.手 ...
- 2.TCP/IP的三次握手与四次挥手
参考文章:http://357742954.blog.51cto.com/368705/1317226 TCP(Transmission Control Protocol) 传输控制协议,是一个面向连 ...
- 用mybatis将SQL查询语句”select * from user”的封装为配置文件
用mybatis将SQL查询语句”select * from user”的封装为配置文件 定义一个xml映射文件,文件名见名知意.如user-mapper.xml,文件内容如下: <?xml v ...
- eclipse导入项目后出现红色叉号的解决方案
对于一名程序员来说,我导入的项目在项目的名称上无端加了一个红色的叉号,虽然这个不友好的符号,对于我整个的项目运行没有任何影响,但是总让我觉得不舒服,大大的叉号写在我的项目的脑袋上,我心里能舒服吗?于是 ...
- web.py之cookie和session
官方给的session例子这里就不讲了.下面直接将怎么设置session,取session: session相关代码一定要放在web.py框架的Main.py里面. # Main.py # 设置ses ...
- 数据库—Innodb中的MVVC
文章:Innodb中的MVVC 地址:https://www.jianshu.com/p/7e967d291c24
- webpack中css文件的代码分割
module.exports = { output: { filename: '[name].js', chunkFilename: '[name].chunk.js', path: path.res ...
- 2.webpack最基本的使用方式
什么是webpack? webpack是前端的一个项目构建工具,它是基于Node.js开发出来的一个前端工具: webpack安装的两种方式 1.运行 'npm i webpack -g' 全局安装w ...