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开始支持的一种语 ...
随机推荐
- 案例-使用MapReduce实现join操作
哈喽-各位小伙伴们中秋快乐,好久没更新新的文章啦,今天分享如何使用mapreduce进行join操作. 在离线计算中,我们常常不只是会对单一一个文件进行操作,进行需要进行两个或多个文件关联出更多数据, ...
- 注解@Slf4j使用
我们在写代码的时候需要加入日志打印,如果不想每次都写private final Logger logger = LoggerFactory.getLogger(XXX.class); 那么可以用注解 ...
- 批量删除checkbox前台后台
<%@ page contentType="text/html;charset=UTF-8" %><%@ include file="/WEB-INF/ ...
- mysql打印用户权限的小技巧
mysql5.5 5.6 SHOW GRANTS FOR mysql> SELECT DISTINCT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host ...
- MySQL的启动方式
MySQL常用启动方式: windows 和linux 上都可以使用 mysql --help|grep my.cnf 过滤查看关于MySQL对应 配置文件my.cnf [root@bqh-118 b ...
- rt-thread下调试elmfat 问题记录
硬件平台:stm32f107 SPI flash:w25q32 RTT版本:v2.1 w25q32的驱动大神们已经写好(w25qxx.c),我只需要照猫画虎的实现相应SPI的驱动程序即可(bsp例 ...
- Go语言——值方法 & 指针方法
1 package main import ( "fmt" "sort" ) type SortableStrings []string type Sortab ...
- MySQL授权(用户权限)
一.mysql查询与权限 (二)授权 用户管理: 设置用户密码 前期准备工作: 停止服务 将配置文件当中的skip-grant-tables删除掉 重启服务: 执行修改命令 查看用户状态(如果数据过多 ...
- WebApplication 启动类一定要存于某个包下
否则spring启动器 无法识别 包类目录
- PHP通过iconv将字符串从GBK转换为UTF8字符集
PHP通过iconv将字符串从GBK转换为UTF8字符集的方法,需要的朋友可以参考下. 1. iconv()介绍 iconv函数可以将一种已知的字符集文件转换成另一种已知的字符集文件.例如:从GB23 ...