ProgrammingPython開発者(asyncio/バックエンド)

Pythonにおける非同期コンテキストマネージャ(async context manager)とは何か、それをどのように実装し、どのような場合に必要不可欠か?

Hintsage AIアシスタントで面接を突破

答え。

非同期コンテキストマネージャとは、非同期メソッド __aenter__ および __aexit__ を定義し、async with 構文で使用されるオブジェクトです。このマネージャは、非同期関数におけるリソースの正しいオープン/クローズを行うために必要です:データベース接続、ファイル、セッションなど。

実装例:

class AsyncDBConnection: async def __aenter__(self): self.conn = await async_db_connect() return self.conn async def __aexit__(self, exc_type, exc, tb): await self.conn.close() async def main(): async with AsyncDBConnection() as conn: await conn.query('SELECT 1')

非同期コンテキストは、技術的な遅延によってイベントループがブロックされることを防ぎ、同時プログラムのパフォーマンスを向上させます。

落とし穴のある質問。

async def 内で通常の with を使用することはできますか?

答え: はい、しかしコンテキストマネージャ内で操作が awaitable(await が必要)な場合、確実に async with が必要です。通常の with は非同期の enter/exit をサポートせず、イベントループがブロックされるか、enter/exit 内で await を呼び出すとエラーが発生します。

例:

async def foo(): with open('file.txt') as f: # 問題なし、同期的に読み取る data = f.read() # しかし通常のコンテキスト内で await はできません、async with 内のみ可能です。

このテーマの細かい点を知らないことで実際に発生したエラーの例。


事例

プロジェクト: 非同期APIを持つウェブサービス。

問題: データベース接続マネージャーが通常の with を使用していましたが、内部で await が呼び出されていました。これにより、RuntimeError("Cannot use 'await' outside async function") エラーが発生し、プロダクション環境でイベントループがブロックされました。


事例

プロジェクト: Websocketsを使用したチャット。

問題: 接続を扱う際に websocket リソースが閉じられず(通常の同期マネージャを使用)、メモリリークと接続のハング状態を引き起こしました。


事例

プロジェクト: マルチスレッド非同期ジョブキュー。

問題: タスクマネージャーが __aexit__ を正しく実装せず、awaitable を返すのを忘れていました。このため、タスクの終了が保証されず、一部のタスクがシステム内で「ハング」しました。