异步上下文管理器

前面文章我们提到了上下文管理器,但是这个上下文管理器只适用于同步代码,不能用于异步代码(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之异步上下文管理器的更多相关文章

  1. 深入Asyncio(七)异步上下文管理器

    Async Context Managers: async with 在某些场景下(如管理网络资源的连接建立.断开),用支持异步的上下文管理器是很方便的. 那么如何理解async with关键字? 先 ...

  2. python 黑魔法 ---上下文管理器(contextor)

    所谓上下文 计算机上下文(Context)对于我而言,一直是一个很抽象的名词.就像形而上一样,经常听见有人说,但是无法和现实认知世界相结合. 最直观的上下文,莫过于小学的语文课,经常会问联系上下文,推 ...

  3. (转)Python中的上下文管理器和Tornado对其的巧妙应用

    原文:https://www.binss.me/blog/the-context-manager-of-python-and-the-applications-in-tornado/ 上下文是什么? ...

  4. Python 上下文管理器模块--contextlib

    在 Python 处理文件的时候我们使用 with 关键词来进行文件的资源关闭,但是并不是只有文件操作才能使用 with 语句.今天就让我们一起学习 Python 中的上下文管理 contextlib ...

  5. Python 的上下文管理器是怎么设计的?

    花下猫语:最近,我在看 Python 3.10 版本的更新内容时,发现有一个关于上下文管理器的小更新,然后,突然发现上下文管理器的设计 PEP 竟然还没人翻译过!于是,我断断续续花了两周时间,终于把这 ...

  6. python2.7高级编程 笔记一(Python中的with语句与上下文管理器学习总结)

    0.关于上下文管理器上下文管理器是可以在with语句中使用,拥有__enter__和__exit__方法的对象. with manager as var: do_something(var) 相当于以 ...

  7. 翻译《Writing Idiomatic Python》(五):类、上下文管理器、生成器

    原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...

  8. python学习笔记4(对象/引用;多范式; 上下文管理器)

    ### Python的强大很大一部分原因在于,它提供有很多已经写好的,可以现成用的对象 21. 动态类型:对象/引用 对象和引用: 对象是储存在内存中的实体,对象名只是指向这一对象的引用(refere ...

  9. Python深入02 上下文管理器

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 上下文管理器(context manager)是Python2.5开始支持的一种语 ...

随机推荐

  1. 可视化利器 TensorBoard

    人工智能的黑盒: TensorBoard 的作用: 1.用TensorFlow保存图的信息到日志中 tfsummary.FileWriter("日志保存路径", sess.grap ...

  2. 冒泡(bubblesort)、选择排序、插入排序、快速排序

    冒泡排序(bubblesort) 特点:通过换位置的方式,一直向上冒泡 package main import "fmt" func bubbleSortAsc(arrayA [] ...

  3. Python 生成动态变量 调用动态变量

    动态生成变量: variable = locals() for i in range(10): variable['A'+str(i)] = 123 print(A8) 调用动态变量: v = loc ...

  4. cygwin_exception::open_stackdumpfile: Dumping stack trace to HttpServer.exe.stackdump错误

    本来,我在Windows下使用Cygwin编译运行c程序,在执行*.exe时报出如题错误,我在Linux环境下使用gcc编译运行,则正常. 所以,当你无法解决上述问题时,换系统吧!

  5. pycharm2017.3版本永久激活

    1.下载破解文件 链接:https://pan.baidu.com/s/1nwI278l 密码:j3gt 2.修改检测文件 ,在文件后缀是vmoptions的 文件中加入(注意是文件中,不是文件后缀上 ...

  6. httpd-2.4源码编译

    APR     APR(Apache portable Run-time libraries,Apache可移植运行库) 主要为上层的应用程序提供一个可以跨越多操作系统平台使用的底层支持接口库.在早 ...

  7. 控制台警告libpng warning: iCCP: known incorrect sRGB profile

    用控制台测试数据的时候,出现的这个问题.虽然只是一个警告但是看着就是不太舒服 ,见下图 弄了好长时间,无意间切换个输入法,原先使用的是QQ输入法 切换成微软五笔以后,竟然好了 好了 好了

  8. Jupyter的学习

    一 .Jupyter中的魔术命令 %load test.py  :”可以将test.py 中的文件加载到jupyter框中 %matplotlib inline :可以将Matplotlib 的结果嵌 ...

  9. python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色)

    python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色) 前言 在 python 开发中,有时候想通过cmd窗口来和用户交互,比如显示信息之类的,会比自己创建 GUI 来的方便,但是随之而 ...

  10. laravel本地开发环境的安装及配置 - Windows:安装 Laravel Homestead 虚拟机

    一.安装 VirtualBox-5.2.22-126460-Win.exe 和 vagrant_2.2.2_x86_64.msi(可视化安装包安装); 安装在D盘 二.导入 Homestead Vag ...