异步上下文管理器

前面文章我们提到了上下文管理器,但是这个上下文管理器只适用于同步代码,不能用于异步代码(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. charles 的安装和手机配置 (我用的win7系统 ,和 iphone8 的配置)

    2018/12/17 由于想抓一下某个手机上app的数据,然后就装了charles,纯记录一下,便于以后不用再查资料.个人参考的网址:https://blog.csdn.net/weixin_4233 ...

  2. JavaScript_day01

    1.变量声明 怎么声明变量? JavaScript中变量声明用的关键字是 var 变量名称. 变量名称命名有什么限制? 变量名称命名需规范,准则:不能以数字开头,不能含有特殊字符(css的属性),可以 ...

  3. 谷歌浏览器调试手机app内置网页

    当自己的H5项目内置于手机app内时,遇到了样式问题或者想查看H5页面代码.数据交互以及缓存等情况来检查数据,此时可以使用谷歌浏览器的控制台远程调试手机,步骤如下: 一.手机开启允许usb调试 二.手 ...

  4. 2.TCP/IP的三次握手与四次挥手

    参考文章:http://357742954.blog.51cto.com/368705/1317226 TCP(Transmission Control Protocol) 传输控制协议,是一个面向连 ...

  5. 用mybatis将SQL查询语句”select * from user”的封装为配置文件

    用mybatis将SQL查询语句”select * from user”的封装为配置文件 定义一个xml映射文件,文件名见名知意.如user-mapper.xml,文件内容如下: <?xml v ...

  6. eclipse导入项目后出现红色叉号的解决方案

    对于一名程序员来说,我导入的项目在项目的名称上无端加了一个红色的叉号,虽然这个不友好的符号,对于我整个的项目运行没有任何影响,但是总让我觉得不舒服,大大的叉号写在我的项目的脑袋上,我心里能舒服吗?于是 ...

  7. web.py之cookie和session

    官方给的session例子这里就不讲了.下面直接将怎么设置session,取session: session相关代码一定要放在web.py框架的Main.py里面. # Main.py # 设置ses ...

  8. 数据库—Innodb中的MVVC

    文章:Innodb中的MVVC 地址:https://www.jianshu.com/p/7e967d291c24

  9. webpack中css文件的代码分割

    module.exports = { output: { filename: '[name].js', chunkFilename: '[name].chunk.js', path: path.res ...

  10. 2.webpack最基本的使用方式

    什么是webpack? webpack是前端的一个项目构建工具,它是基于Node.js开发出来的一个前端工具: webpack安装的两种方式 1.运行 'npm i webpack -g' 全局安装w ...