Heim  >  Artikel  >  Backend-Entwicklung  >  Async-Kontextmanager beherrschen: Steigern Sie die Leistung Ihres Python-Codes

Async-Kontextmanager beherrschen: Steigern Sie die Leistung Ihres Python-Codes

Susan Sarandon
Susan SarandonOriginal
2024-11-26 14:18:11909Durchsuche

Mastering Async Context Managers: Boost Your Python Code

Asynchrone Kontextmanager in Python verändern den Umgang mit Ressourcen in gleichzeitigen Anwendungen grundlegend. Sie sind wie normale Kontextmanager, aber mit einer Besonderheit: Sie arbeiten nahtlos mit asynchronem Code zusammen.

Beginnen wir mit den Grundlagen. Um einen asynchronen Kontextmanager zu erstellen, müssen wir zwei spezielle Methoden implementieren: __aenter__ und __aexit__. Dies sind die asynchronen Versionen von __enter__ und __exit__, die wir in regulären Kontextmanagern verwenden.

Hier ist ein einfaches Beispiel:

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())

In diesem Beispiel simulieren wir die asynchrone Erfassung und Freigabe einer Ressource. Die async with-Anweisung sorgt dafür, dass __aenter__ und __aexit__ zum richtigen Zeitpunkt aufgerufen werden.

Lassen Sie uns nun darüber sprechen, warum asynchrone Kontextmanager so nützlich sind. Sie eignen sich perfekt für die nicht blockierende Verwaltung von Ressourcen, die asynchrone Vorgänge erfordern, wie Datenbankverbindungen, Netzwerk-Sockets oder Dateihandler.

Nehmen Sie zum Beispiel Datenbankverbindungen. Wir können einen asynchronen Kontextmanager erstellen, der einen Verbindungspool verwaltet:

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())

Dieses Setup stellt sicher, dass wir unsere Datenbankverbindungen effizient verwalten. Der Pool wird erstellt, wenn wir den Kontext betreten, und ordnungsgemäß geschlossen, wenn wir ihn verlassen.

Die Fehlerbehandlung in asynchronen Kontextmanagern ist ähnlich wie bei regulären. Die Methode __aexit__ empfängt Ausnahmeinformationen, wenn im Kontext ein Fehler auftritt. Wir können diese Fehler behandeln oder sie sich verbreiten lassen:

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())

In diesem Beispiel unterdrücken wir ValueError, erlauben aber die Ausbreitung anderer Ausnahmen.

Asynchrone Kontextmanager eignen sich auch hervorragend für die Implementierung verteilter Sperren. Hier ist ein einfaches Beispiel mit 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())

Diese Sperre stellt sicher, dass immer nur ein Prozess den kritischen Abschnitt gleichzeitig ausführen kann, auch über mehrere Maschinen hinweg.

Wir können auch asynchrone Kontextmanager für Transaktionsbereiche verwenden:

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)

Dieses Setup stellt sicher, dass unsere Datenbanktransaktionen auch bei Ausnahmen immer ordnungsgemäß festgeschrieben oder zurückgesetzt werden.

Asynchrone Kontextmanager können mit anderen asynchronen Grundelementen kombiniert werden, um noch leistungsfähigere Muster zu erhalten. Wir können sie beispielsweise mit asyncio.gather für die parallele Ressourcenverwaltung verwenden:

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

Dadurch können wir mehrere Daten gleichzeitig verarbeiten und gleichzeitig eine ordnungsgemäße Ressourcenverwaltung gewährleisten.

Zusammenfassend lässt sich sagen, dass asynchrone Kontextmanager ein leistungsstarkes Tool zum Verwalten von Ressourcen in asynchronem Python-Code sind. Sie bieten eine saubere, intuitive Möglichkeit für die asynchrone Einrichtung und Demontage, Fehlerbehandlung und Ressourcenbereinigung. Wenn Sie asynchrone Kontextmanager beherrschen, sind Sie bestens gerüstet, um robuste, skalierbare Python-Anwendungen zu erstellen, die komplexe, gleichzeitige Arbeitsabläufe problemlos bewältigen können.


Unsere Kreationen

Schauen Sie sich unbedingt unsere Kreationen an:

Investor Central | Intelligentes Leben | Epochen & Echos | Rätselhafte Geheimnisse | Hindutva | Elite-Entwickler | JS-Schulen


Wir sind auf Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Wissenschaft & Epochen Medium | Modernes Hindutva

Das obige ist der detaillierte Inhalt vonAsync-Kontextmanager beherrschen: Steigern Sie die Leistung Ihres Python-Codes. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn