ホームページ  >  記事  >  バックエンド開発  >  非同期コンテキスト マネージャーをマスターする: Python コードのパフォーマンスを向上させる

非同期コンテキスト マネージャーをマスターする: Python コードのパフォーマンスを向上させる

Susan Sarandon
Susan Sarandonオリジナル
2024-11-26 14:18:11909ブラウズ

Mastering Async Context Managers: Boost Your Python Code

Python の非同期コンテキスト マネージャーは、同時アプリケーションでリソースを処理するための革新的なツールです。これらは通常のコンテキスト マネージャーに似ていますが、ひねりが加えられており、非同期コードとシームレスに動作します。

基本から始めましょう。非同期コンテキスト マネージャーを作成するには、__aenter__ と __aexit__ という 2 つの特別なメソッドを実装する必要があります。これらは、通常のコンテキスト マネージャーで使用する __enter__ と __exit__ の非同期バージョンです。

これは簡単な例です:

class AsyncResource:
    async def __aenter__(self):
        print("Acquiring resource")
        await asyncio.sleep(1)  # Simulating async acquisition
        return self

    async def __aexit__(self, exc_type, exc_value, traceback):
        print("Releasing resource")
        await asyncio.sleep(1)  # Simulating async release

async def main():
    async with AsyncResource() as resource:
        print("Using resource")

asyncio.run(main())

この例では、リソースの非同期取得と解放をシミュレートしています。 async with ステートメントは、適切なタイミングで __aenter__ と __aexit__ の呼び出しを処理します。

ここで、非同期コンテキスト マネージャーがなぜ非常に便利なのかについて話しましょう。これらは、データベース接続、ネットワーク ソケット、ファイル ハンドラーなどの非同期操作を必要とするリソースをブロックしない方法で管理するのに最適です。

データベース接続を例に考えてみましょう。接続プールを管理する非同期コンテキスト マネージャーを作成できます。

import asyncpg

class DatabasePool:
    def __init__(self, dsn):
        self.dsn = dsn
        self.pool = None

    async def __aenter__(self):
        self.pool = await asyncpg.create_pool(self.dsn)
        return self.pool

    async def __aexit__(self, exc_type, exc_value, traceback):
        await self.pool.close()

async def main():
    async with DatabasePool('postgresql://user:password@localhost/db') as pool:
        async with pool.acquire() as conn:
            result = await conn.fetch('SELECT * FROM users')
            print(result)

asyncio.run(main())

この設定により、データベース接続を効率的に管理できるようになります。プールはコンテキストに入るときに作成され、コンテキストから出るときに適切に閉じられます。

非同期コンテキスト マネージャーでのエラー処理は、通常のエラー処理と似ています。 __aexit__ メソッドは、コンテキスト内でエラーが発生した場合に例外情報を受け取ります。これらのエラーを処理することも、伝播させることもできます:

class ErrorHandlingResource:
    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_value, traceback):
        if exc_type is ValueError:
            print("Caught ValueError, suppressing")
            return True  # Suppress the exception
        return False  # Let other exceptions propagate

async def main():
    async with ErrorHandlingResource():
        raise ValueError("Oops!")
    print("This will be printed")

    async with ErrorHandlingResource():
        raise RuntimeError("Unhandled!")
    print("This won't be printed")

asyncio.run(main())

この例では、ValueError を抑制していますが、他の例外の伝播は許可しています。

非同期コンテキスト マネージャーは、分散ロックの実装にも最適です。 Redis を使用した簡単な例を次に示します。

import aioredis

class DistributedLock:
    def __init__(self, redis, lock_name, expire=10):
        self.redis = redis
        self.lock_name = lock_name
        self.expire = expire

    async def __aenter__(self):
        while True:
            locked = await self.redis.set(self.lock_name, "1", expire=self.expire, nx=True)
            if locked:
                return self
            await asyncio.sleep(0.1)

    async def __aexit__(self, exc_type, exc_value, traceback):
        await self.redis.delete(self.lock_name)

async def main():
    redis = await aioredis.create_redis_pool('redis://localhost')
    async with DistributedLock(redis, "my_lock"):
        print("Critical section")
    await redis.close()

asyncio.run(main())

このロックにより、複数のマシンにまたがる場合でも、一度に 1 つのプロセスのみがクリティカル セクションを実行できるようになります。

トランザクション スコープに非同期コンテキスト マネージャーを使用することもできます。

class AsyncTransaction:
    def __init__(self, conn):
        self.conn = conn

    async def __aenter__(self):
        await self.conn.execute('BEGIN')
        return self

    async def __aexit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            await self.conn.execute('COMMIT')
        else:
            await self.conn.execute('ROLLBACK')

async def transfer_funds(from_account, to_account, amount):
    async with AsyncTransaction(conn):
        await conn.execute('UPDATE accounts SET balance = balance -  WHERE id = ', amount, from_account)
        await conn.execute('UPDATE accounts SET balance = balance +  WHERE id = ', amount, to_account)

この設定により、例外が発生した場合でも、データベース トランザクションが常に適切にコミットまたはロールバックされます。

非同期コンテキスト マネージャーを他の非同期プリミティブと組み合わせて、さらに強力なパターンを実現できます。たとえば、これらを asyncio.gather とともに使用して、並列リソース管理を行うことができます。

async def process_data(data):
    async with ResourceManager() as rm:
        results = await asyncio.gather(
            rm.process(data[0]),
            rm.process(data[1]),
            rm.process(data[2])
        )
    return results

これにより、適切なリソース管理を確保しながら、複数のデータを並行して処理できるようになります。

結論として、非同期コンテキスト マネージャーは、非同期 Python コードでリソースを管理するための強力なツールです。これらは、非同期のセットアップとティアダウン、エラー処理、リソースのクリーンアップを処理するクリーンで直感的な方法を提供します。非同期コンテキスト マネージャーをマスターすると、複雑な同時ワークフローを簡単に処理できる、堅牢でスケーラブルな Python アプリケーションを構築する準備が整います。


私たちの作品

私たちの作品をぜひチェックしてください:

インベスターセントラル | スマートな暮らし | エポックとエコー | 不可解な謎 | ヒンドゥーヴァ | エリート開発者 | JS スクール


私たちは中程度です

Tech Koala Insights | エポックズ&エコーズワールド | インベスター・セントラル・メディア | 不可解な謎 中 | 科学とエポックミディアム | 現代ヒンドゥーヴァ

以上が非同期コンテキスト マネージャーをマスターする: Python コードのパフォーマンスを向上させるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。