9.1 コンテキストマネージャー
withオペレーターを使ってリソースへのアクセスを制御した方法、覚えてる?これを使うと、リソースがいつ使われ始めて、いつ終了したかを正確に追跡できたよね。これを「非同期リソース」に対しても同じことができるんだ。
非同期コンテキストマネージャー(AsyncContextManager)は、非同期プログラミングにおけるリソースの管理に使われて、非同期関数内でリソースを正しく開閉するのを保証するよ。通常のコンテキストマネージャーと似てるけど、非同期関数でasync withキーワードと一緒に使われるんだ。
詳しくは説明しないけど、近い将来、きみたちが自分の非同期コンテキストマネージャーを作ることはないからね。始めるころにはどうせ忘れてるだろうし。でも概念を紹介したいんだ。
非同期コンテキストマネージャーの作成
非同期コンテキストマネージャーは、__aenter__と__aexit__メソッドを使用して定義されるよ。これらのメソッドは通常のコンテキストマネージャーの__enter__と__exit__メソッドに似てるけど、非同期なんだ。
-
__aenter__(): コンテキストに入るときに呼び出される非同期メソッド。 -
__aexit__(exc_type, exc, tb): コンテキストを出るときに呼び出される非同期メソッド。例外のタイプ、例外そのもの、トレースバック(traceback)の3つの引数を受け取るよ。
非同期コンテキストマネージャーを作る例
import asyncio
class AsyncContextManager:
async def __aenter__(self):
print("Enter context")
return self
async def __aexit__(self, exc_type, exc, tb):
print("Exit context")
async def main():
async with AsyncContextManager():
print("Inside context")
asyncio.run(main())
このコードはこんな感じで実行されるよ:
- 非同期で
main()関数が開始される main()関数が実行を開始するAsyncContextManager型のオブジェクトが作成されるAsyncContextManagerオブジェクトの__aenter__()メソッドが呼び出されるprint("Enter context")が出力されるprint("Inside context")のコードが実行されるAsyncContextManagerオブジェクトの__aexit__()メソッドが呼び出されるmain()関数の実行が終了する
9.2 使用例
前の例では、必ずしも非同期バージョンのコンテキストマネージャーを使う必要はないんだ。同期バージョンにしてもコードは動くよ。
でも、もしwithブロックの中で非同期関数を呼び出すか、awaitオペレーターを使う場合、非同期マネージャーが必要なんだ。
ファイル操作のための非同期コンテキストマネージャー
この例では、ファイルの非同期読み書きにaiofilesライブラリを使うよ。非同期コンテキストマネージャーaiofiles.openは、非同期コンテキストでファイルを安全に開閉するのを可能にするよ。
import aiofiles
import asyncio
async def main():
async with aiofiles.open('example.txt', mode='w') as file:
await file.write('Hello, world!')
asyncio.run(main())
ネットワーク操作のための非同期コンテキストマネージャー
この例では、非同期HTTPリクエストを実行するためにaiohttpライブラリを使うよ。非同期コンテキストマネージャーClientSessionとsession.getは、接続の管理を正しく行うんだ。
import aiohttp
import asyncio
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
html = await fetch('https://example.com')
print(html)
asyncio.run(main())
非同期コンテキストマネージャーは、ファイルやネットワーク接続、その他開閉が必要なリソースの自動的な管理を提供してくれるんだ。
__aenter__と__aexit__メソッドは、コンテキストへの入出時に非同期操作を行うことを可能にして、タスクの並列実行を保証するんだ。非同期コンテキストマネージャーを使うことで、リソースリークを避け、すべてのリソースが正しく解放されることを保証できるよ。
GO TO FULL VERSION