Pythons asynchrones Web-Potenzial mit ASGI freischalten
Takashi Yamamoto
Infrastructure Engineer · Leapcell

Einleitung
die Landschaft der Webentwicklung entwickelt sich ständig weiter, angetrieben durch steigende Anforderungen an Reaktionsfähigkeit, Skalierbarkeit und Effizienz. Traditionelle synchrone Python-Web-Frameworks, obwohl robust und weit verbreitet, stießen oft an ihre Grenzen, wenn es um die gleichzeitige Behandlung von E/A-gebundenen Operationen ging. Stellen Sie sich einen Webserver vor, der darauf wartet, dass eine Datenbankabfrage abgeschlossen wird oder ein externer API-Aufruf zurückkehrt, bevor er eine andere Client-Anfrage bearbeiten kann. Dieses "blockierende" Verhalten führt unweigerlich zu Leistungsengpässen und reduziertem Durchsatz, insbesondere unter hoher Last. Die inhärente Single-Threaded-Natur von synchronem serverseitigem Code wurde zu einem erheblichen Hindernis für die Erstellung moderner, hochleistungsfähiger Webanwendungen in Python.
Hier kommt die Asynchronous Server Gateway Interface, kurz ASGI, ins Spiel. ASGI entstand als eine zentrale Spezifikation, die diese Lücke schließen soll und die Art und Weise, wie Python-Web-Frameworks mit asynchronen Servern interagieren, grundlegend verändert hat. Durch die Übernahme von Non-Blocking-E/A und asynchronen Programmierparadigmen hat ASGI eine neue Ära für die Python-Webentwicklung eingeläutet und Entwickler in die Lage versetzt, hochgradig gleichzeitige und skalierbare Anwendungen zu erstellen, die Tausende von gleichzeitigen Verbindungen effizient handhaben können. In diesem Artikel werden wir uns mit den Feinheiten von ASGI befassen und verstehen, wie es funktioniert, seine Vorteile und wie es die Zukunft der asynchronen Python-Webdienste gestaltet.
Das asynchrone Gateway verstehen
Um ASGI wirklich zu schätzen, müssen wir zuerst einige Kernkonzepte verstehen, die der asynchronen Programmierung in Python und dem Webserver-Ökosystem zugrunde liegen.
Kernterminologie:
- Asynchrone Programmierung: Ein Programmierparadigma, das es ermöglicht, mehrere Aufgaben gleichzeitig auszuführen, ohne den Hauptprogramm-Thread zu blockieren. Anstatt darauf zu warten, dass eine Operation abgeschlossen wird, kann das Programm zu einer anderen Aufgabe wechseln und die ursprüngliche wieder aufnehmen, wenn sie bereit ist. In Python wird dies hauptsächlich mit der
async
/await
-Syntax und derasyncio
-Bibliothek erreicht. - Synchrone Programmierung: Ein Programmierparadigma, bei dem Aufgaben sequenziell ausgeführt werden. Jeder Vorgang muss abgeschlossen sein, bevor der nächste beginnen kann, was potenziell zu "blockierendem" Verhalten führt.
- Blockierende E/A: Eine Operation, bei der die Programmausführung anhält, bis eine bestimmte Ein-/Ausgabeoperation (z. B. Lesen von einer Festplatte, Herstellen einer Netzwerkanfrage) abgeschlossen ist.
- Non-Blocking E/A: Eine Operation, die es dem Programm ermöglicht, andere Aufgaben auszuführen, während es auf den Abschluss einer E/A-Operation wartet, typischerweise indem es benachrichtigt wird, wenn die Operation bereit ist.
- WSGI (Web Server Gateway Interface): Der langjährige synchrone Standard-Interface zwischen Python-Webservern und Web-Anwendungsframeworks. Es definiert ein einfaches, aufrufbasiertes Interface zur Behandlung von HTTP-Anfragen.
- ASGI (Asynchronous Server Gateway Interface): Der asynchrone Nachfolger von WSGI, der für die Unterstützung asynchroner Operationen, WebSockets und Long-Polling in Python-Webanwendungen entwickelt wurde. Es basiert auf einem
async
-Funktionsaufruf, der die Argumentescope
,receive
undsend
akzeptiert. - Webserver (ASGI-Server): Ein Programm, das auf eingehende Netzwerkanfragen (z. B. HTTP) lauscht und diese an die entsprechende Anwendung weiterleitet. Beispiele sind Uvicorn, Hypercorn und Daphne.
- ASGI-Anwendung: Ein Python-Aufruf (eine
async
-Funktion oder eine Klasse mit einer__call__
-Methode), die der ASGI-Spezifikation entspricht. Dies sind im Wesentlichen Ihr Web-Framework oder Ihre Anwendungslogik.
Wie ASGI funktioniert:
Im Kern fungiert ASGI als universelles Interface zwischen asynchronen Python-Webservern (wie Uvicorn) und asynchronen Webanwendungen (wie FastAPI oder Starlette). Im Gegensatz zur einzigen, synchronen callable(environ, start_response)
-Signatur von WSGI definiert ASGI ein async
-Callable mit drei Kernargumenten:
async def application(scope, receive, send): # ... Anwendungslogik ...
scope
: Dies ist ein Dictionary, das alle anfragespezifischen Details enthält, ähnlich wie dieenviron
von WSGI, aber für asynchrone Kontexte konzipiert. Es enthält Informationen wie HTTP-Methode, Pfad, Header, Verbindungsdetails und Ereignistyp (z. B.'http'
,'websocket'
,'lifespan'
).
- Bei einer HTTP-Anfrage enthält
scope
Details wietype='http'
,method
,path
,headers
,query_string
usw. - Bei einer WebSocket-Verbindung hat
scope
type='websocket'
zusammen mitpath
,headers
,subprotocols
usw.
receive
: Dies ist einawait
able Callable, das es der Anwendung ermöglicht, eingehende Nachrichten vom Server zu empfangen. Diese Nachrichten sind typischerweise Ereignisse wie Client-Daten, Verbindungsabbrüche oder Lebenszyklusereignisse. Jede empfangene Nachricht ist ein Dictionary, das den Ereignistyp und die damit verbundenen Daten enthält.
- Für HTTP kann
receive
'http.request'
-Nachrichten mit den Anforderungs-Body-Chunks liefern. - Für WebSockets kann
receive
'websocket.receive'
-Nachrichten mit Text- oder Binärdaten vom Client liefern.
send
: Dies ist einawait
able Callable, das es der Anwendung ermöglicht, Nachrichten an den Server zurückzusenden, der sie dann an den Client weiterleitet. Diese Nachrichten stellen Antworten, Daten oder Steuersignale dar.
- Für HTTP wird
send
verwendet, um Nachrichten vom Typ'http.response.start'
(Statuscode, Header) und'http.response.body'
(Antwort-Body-Chunks) zu senden. - Für WebSockets wird
send
verwendet, um Nachrichten vom Typ'websocket.send'
(Text- oder Binärdaten) oder'websocket.close'
zu senden.
Ein einfaches ASGI-Anwendungsbeispiel (Barebones-HTTP):
Werfen wir einen Blick auf eine minimalistische ASGI-Anwendung, die auf eine HTTP-Anfrage antwortet:
async def homepage_application(scope, receive, send): if scope['type'] == 'http': # HTTP-Anfragebehandlung await send({ 'type': 'http.response.start', 'status': 200, 'headers': [ [b'content-type', b'text/plain'], ], }) await send({ 'type': 'http.response.body', 'body': b'Hello, ASGI World!', }) elif scope['type'] == 'websocket': # WebSocket-Behandlung (vereinfacht zur Demonstration) await send({ 'type': 'websocket.accept' }) while True: message = await receive() if message['type'] == 'websocket.receive': print(f"Received from WebSocket: {message['text']}") await send({ 'type': 'websocket.send', 'text': f"Echo: {message['text']}" }) elif message['type'] == 'websocket.disconnect': print("WebSocket disconnected") break
Um dies auszuführen, benötigen Sie einen ASGI-Server wie Uvicorn. Installieren Sie zuerst Uvicorn: pip install uvicorn
. Dann können Sie ihn von Ihrem Terminal aus ausführen:
<a id=