Die asynchrone Programmierung wurde in Python mit Version 3.5 durch die Einführung der Schlüsselwörter async und await eingeführt. Zuvor wurden für asynchrone Aufgaben Bibliotheken wie asyncio und Generatoren auf Basis von Koroutinen verwendet, was oft schwierig zu verstehen und zu warten war. Mit dem neuen async/await-Syntax wurde der asynchrone Code jedoch klarer und lesbarer und ähnelte dem gewohnten synchronen Stil.
Vor der Einführung von async/await wurde die Asynchronität durch Rückrufe und Generatoren (z. B. mit der Bibliothek tornado oder alten asyncio-APIs) implementiert. Solcher Code war schwer zu debuggen und zu warten.
Das Hauptproblem bei der Verarbeitung einer großen Anzahl gleichzeitiger I/O-Operationen (Netzwerkanfragen, Datei-Ein/Ausgaben) in synchronem Code ist die Blockierung des Hauptthreads. Dies führt zu einer verminderten Leistung und einer ineffizienten Ressourcennutzung.
Die asynchrone Programmierung mit async/await ermöglicht es, viele Ein- und Ausgabeoperationen gleichzeitig in einem einzigen Thread auszuführen, ohne Blockierungen zu verursachen. Der Syntax ist dabei nah an gewöhnlichen Funktionen, was die Lesbarkeit und das Debuggen erleichtert.
import asyncio async def fetch_data(delay): print(f"Start fetching after {delay}s delay") await asyncio.sleep(delay) print(f"Done fetching after {delay}s delay") return delay async def main(): results = await asyncio.gather( fetch_data(1), fetch_data(2), fetch_data(3) ) print("Results:", results) asyncio.run(main())
Kann eine Funktion, die mit async def definiert ist, wie eine normale Funktion aufgerufen werden?
Nein. Der Aufruf einer solchen Funktion gibt ein Koroutinenobjekt zurück, das nicht ausgeführt wird, bis es in die Ereignisschleife übergeben wird (z. B. mit await oder asyncio.run()).
def foo(): return 42 async def bar(): return 42 print(foo()) # 42 print(bar()) # <coroutine object bar at ...>
Kann await außerhalb einer asynchronen Funktion verwendet werden?
Nein. Das Schlüsselwort await darf nur innerhalb von Funktionen verwendet werden, die mit async def deklariert sind. Ein Versuch, await außerhalb einer solchen Funktion zu verwenden, führt zu einem Syntaxfehler.
# Fehler! await asyncio.sleep(1) # SyntaxError: 'await' outside async function
Funktioniert Asynchronität für Operationen, die nicht mit I/O zu tun haben (z. B. Berechnungen)?
Nein. Asynchronität ist nur für Ein- und Ausgabeoperationen effektiv. Für rechenintensive Aufgaben sind nach wie vor multiprocessing oder threading erforderlich, andernfalls wird die Ereignisschleife blockiert.
Vorteile:
Nachteile:
Negativer Fall: Junge Entwickler versuchten, eine Anwendung mit async/await zu beschleunigen, machten jedoch asynchron nur Berechnungen und keine Netzwerkanfragen. Die Anwendung wurde nicht schneller. Vorteile: Sie machten sich mit der Syntax vertraut. Nachteile: kein Gewinn, der Code wurde komplizierter.
Positiver Fall: Asynchron wurden Tausende von Anfragen an die API bearbeitet. Der Server konnte mehr Kunden bedienen, ohne die Ressourcen zu erhöhen. Vorteile: Die Leistung stieg erheblich, die Architektur wurde einfacher. Nachteile: Die Einstiegshürde für Neulinge stieg.