非同期コンテキストマネージャ
私たちが言及した前の記事コンテキストマネージャを、しかし、これが唯一のコンテキストマネージャの同期コードに適用されますが、コードが非同期(非同期DEFフォーム)に使用することはできませんが、我々は非同期にコンテキストマネージャを使用する方法について説明します今日は心配しないでください。
このチュートリアルで使用思い出しPythonのバージョンPython3.7です。
と非同期
非同期コンテキストマネージャ。同期コンテキストマネージャと同様に、我々は表現の基本的な形のための非同期コンテキストマネージャが持つ非同期である一方、それはどのような作品との非同期(async)あなたに伝えるために、コンテキスト管理を使用して次のコードを達成することができます知っています。
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)
aenterとaexitがベースで同期を追加し、実際には、それは非同期を表すためです。
実装、共通機能を用いて達成することができる使用するが、上記の例のように、非同期関数の形で達成する必要のある非同期。
asynccontextmanager
Pythonの3.7からは、非同期コンテキストマネージャを書くための2つの方法があります。一つは、別のは、別のモジュールasynccontextmanagerをcontextlibされ、前述の魔法の機能を達成することです。コンテキストマネージャは、非同期方法デコレータを介して実装します
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クラスは、書き込みを追加読み、保留リストにreadlinesを呼び出すために使用されるメソッドを提供します。これらのタスクは、finallyブロックThreadPoolExecutorイベントループで予定されています。
それは__aenter得前半__()を表す
__aexitの__()を示すために使用歩留まりの半分
のリンクが最終的にリソースを閉じることができ、使用を終え保証することができた後、後で使用するために。
非同期のコンテキストマネージャを実行します
あなたが電話をかけるために使用する必要がキーワードと非同期(async)、前の例非同期コンテキストマネージャを呼び出した場合。また声明で非同期でのみ非同期関数で使用することができます。
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())
同様の方法を使用してのように使用して、そのハンドルを使用して、唯一の注意点は、非同期関数を使用することです。
同期タスク
いくつかの以前の非同期チュートリアルと皆で私たちは、次のコードを見て、コンテキストマネージャによって非同期タスクを同期させるために、これらのメソッドを補完することができます調整プロセス、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.プログラムの形式は、同時出力に同期されます。
- Schedule_coroの役割があり、時間と非同期共同ドライブ作業負荷、作業負荷、workload3は保留中のタスクのリストに追加し、終了し、タスクリストタスクの同時動作に。