Async/Await in Python: Eine vollständige Anleitung zu Coroutines
James Reed
Infrastructure Engineer · Leapcell

Python Asynchrone Programmierung
In Python gibt es verschiedene asynchrone Ansätze, wie z.B. Coroutinen, Multithreading und Multiprocessing. Zusätzlich gibt es einige traditionelle Methoden und asynchrone Bibliotheken von Drittanbietern. Dieser Artikel konzentriert sich hauptsächlich auf Coroutinen und stellt Multithreading und Multiprocessing kurz vor.
async/await
In Python ist eine mit async
deklarierte Funktion eine asynchrone Funktion, die oft als Coroutine bezeichnet wird. Zum Beispiel:
import asyncio async def hello(): await asyncio.sleep(1) print("hello leapcell")
Aufrufmethode
Die Art und Weise, eine asynchrone Funktion aufzurufen, unterscheidet sich ein wenig von der einer regulären Funktion. Hier ist zum Beispiel, wie man eine reguläre Funktion aufruft:
def hello(): print("hello leapcell") hello()
Und hier ist, wie man eine asynchrone Funktion aufruft:
import asyncio async def hello(): await asyncio.sleep(1) print("hello leapcell") h = hello() asyncio.run(h)
Beim Aufruf einer asynchronen Funktion gibt die erste Verwendung von h = hello()
ein Coroutinen-Objekt zurück, und der Code innerhalb der Funktion wird nicht ausgeführt. Erst nach Verwendung der Funktion asyncio.run(h)
oder der Anweisung await h
wird der Code ausgeführt, wie unten gezeigt:
import asyncio async def async_function(): print("This is inside the async function") await asyncio.sleep(1) return "Async function result" # Correct usage async def correct_usage(): print("Correct usage:") result = await async_function() print(f"Result: {result}") # Call without using await def incorrect_usage(): print("\nIncorrect usage:") coroutine = async_function() print(f"Returned object: {coroutine}") # Note: "This is inside the async function" won't be printed here # Handle an unawaited coroutine async def handle_unawaited_coroutine(): print("\nHandling unawaited coroutine:") coroutine = async_function() try: # Use asyncio.run() to run the coroutine result = await coroutine print(f"Result after handling: {result}") except RuntimeWarning as e: print(f"Caught warning: {e}") async def main(): await correct_usage() incorrect_usage() await handle_unawaited_coroutine() asyncio.run(main())
Häufige Methoden zum Aufrufen von asynchronen Funktionen
asyncio.gather()
Die Verwendung von gather
startet mehrere Aufgaben gleichzeitig und führt sie gleichzeitig aus. Nachdem alle Aufgaben abgeschlossen und die Ergebnisse zurückgegeben wurden, wird der nachfolgende Code weiter ausgeführt. Zum Beispiel:
import asyncio async def num01(): await asyncio.sleep(1) return 1 async def num02(): await asyncio.sleep(1) return 2 async def combine(): results = await asyncio.gather(num01(), num02()) print(results) asyncio.run(combine())
Ausgabe:
[1, 2]
Es gibt zwei asynchrone Funktionen oben. Verwenden Sie nun asyncio.gather
, um diese beiden Funktionen gleichzeitig auszuführen, und verwenden Sie dann await
, um auf die Ergebnisse zu warten. Die zurückgegebenen Ergebnisse werden in results
gespeichert.
Direkte Verwendung von await
Die obige gather
-Methode sammelt mehrere asynchrone Funktionen und führt sie gleichzeitig aus. Abgesehen von dieser Methode können Sie auch direkt das Schlüsselwort await
verwenden, wie unten gezeigt:
import asyncio async def hello(): await asyncio.sleep(1) return "hello leapcell" async def example(): result = await hello() print(result) asyncio.run(example())
Ausgabe:
hello leapcell
In der obigen Funktion example
wird await
verwendet, um auf das Ergebnis der asynchronen Funktion zu warten. Nachdem das Ergebnis zurückgegeben wurde, wird es in der Konsole ausgegeben. Diese Methode wird tatsächlich sequentiell ausgeführt, da der Code an der await
-Anweisung wartet, bis das Ergebnis zurückgegeben wird, bevor er mit der Ausführung des folgenden Codes fortfährt.
Was passiert, wenn Sie hier nicht warten? Wenn Sie result = hello()
verwenden, wird der Code in hello()
nicht ausgeführt, und das zurückgegebene result
ist ein Coroutinen-Objekt.
asyncio.create_task()
Neben den obigen Methoden gibt es eine flexiblere Möglichkeit, nämlich die Verwendung von asyncio.create_task()
. Diese Methode erstellt eine Aufgabe und führt sie sofort im Hintergrund aus. Zu diesem Zeitpunkt kann die Hauptfunktion andere Operationen ausführen. Wenn Sie das Ergebnis der asynchronen Aufgabe abrufen müssen, verwenden Sie await
, um es zu erhalten, wie unten gezeigt:
import asyncio async def number(): await asyncio.sleep(1) return 1 async def float_num(): await asyncio.sleep(1) return 1.0 async def example(): n = asyncio.create_task(number()) f = asyncio.create_task(float_num()) print("do something...") print(await n) print(await f) asyncio.run(example())
Ausgabe:
do something...
1
1.0
Aus der obigen Ausgabe können wir sehen, dass create_task
zuerst eine Aufgabe erstellt und startet. Zu diesem Zeitpunkt wird die Hauptfunktion nicht blockiert und setzt die Ausführung des folgenden Codes fort. Wenn Sie das Ergebnis der asynchronen Funktion benötigen, rufen Sie await n
auf, um das Ergebnis zu erhalten. Auf diese Weise können Sie einige zeitaufwändige Aufgaben zur Ausführung in asynchronen Code einfügen und dann bei Bedarf die Ergebnisse dieser asynchronen Funktionen abrufen.
Hinweis: Das Aufrufen einer asynchronen Funktion mit create_task
unterscheidet sich vom Aufrufen wie einer regulären Funktion. Bei Verwendung der regulären Funktionsaufrufmethode number()
wird die Funktion nicht ausgeführt. Wenn Sie jedoch create_task
verwenden, um eine asynchrone Funktion aufzurufen, wird die Funktion sofort ausgeführt. Selbst wenn Sie await
nicht verwenden, um das Ergebnis zu erhalten, wird die Funktion vor dem Beenden der Hauptfunktion abgeschlossen.
Semaphore
asyncio.Semaphore
ist eine Synchronisationsprimitive in der Python-Bibliothek asyncio
, die den Zugriff auf gemeinsam genutzte Ressourcen steuert. Sie ist in der asynchronen Programmierung sehr nützlich und kann die Anzahl der Coroutinen begrenzen, die gleichzeitig auf eine bestimmte Ressource zugreifen können. Wie im folgenden Code gezeigt:
import asyncio import aiohttp async def fetch(url, session, semaphore): async with semaphore: print(f"Fetching {url}") async with session.get(url) as response: return await response.text() async def main(): urls = [ "http://example.com", "http://example.org", "http://example.net", "http://example.edu", "http://example.io", ] semaphore = asyncio.Semaphore(2) # Limit the number of concurrent requests to 2 async with aiohttp.ClientSession() as session: tasks = [fetch(url, session, semaphore) for url in urls] responses = await asyncio.gather(*tasks) for url, response in zip(urls, responses): print(f"URL: {url}, Response length: {len(response)}") asyncio.run(main())
Im obigen Code wird ein asyncio.Semaphore(2)
erstellt, um die Anzahl der gleichzeitigen Anfragen auf 2 zu begrenzen. In der asynchronen Funktion fetch
wird async with semaphore
verwendet, um das Semaphor zu erwerben und freizugeben. Vor dem Betreten wird automatisch die Methode acquire()
aufgerufen, um das Semaphor zu erwerben, und beim Verlassen des with
-Blocks wird die Methode release()
aufgerufen, um das Semaphor freizugeben. Die Verwendung von Semaphore
kann die Anzahl der gleichzeitigen Anfragen steuern und so eine übermäßige Belastung des Servers verhindern. Dies ist sehr nützlich beim Umgang mit begrenzten Ressourcen, wie z. B. Datenbankverbindungen. Gleichzeitig kann es die Systemleistung optimieren und das Gleichgewicht der Gleichzeitigkeit finden.
Semaphore-Prinzip
Im Inneren wird ein Zähler geführt. Wenn der Zähler größer als Null ist, ist der Zugriff erlaubt; wenn er gleich Null ist, ist der Zugriff verboten. Die Methoden zum Erwerben und Freigeben des Zählers sind acquire()
bzw. release()
. Sie müssen bei der Initialisierung einen anfänglichen Zählerwert angeben. Steuern Sie dann die Anzahl der gleichzeitigen Anfragen, indem Sie den Zählerwert im Code steuern.
Multithreading
Multithreading ist eine traditionelle Methode zur gleichzeitigen Ausführung von Aufgaben und eignet sich für E/A-gebundene Aufgaben, wie im folgenden Beispiel gezeigt:
import threading import time def worker(name): print(f"Worker {name} starting") time.sleep(2) # Simulate a time - consuming operation print(f"Worker {name} finished") def main(): threads = [] for i in range(3): t = threading.Thread(target=worker, args=(i,)) threads.append(t) t.start() for t in threads: t.join() print("All workers finished") if __name__ == "__main__": main()
Das t.join()
im Multithreading wird verwendet, um auf den Abschluss von drei Threads zu warten. Wenn die Methode join()
für ein Thread- oder Prozessobjekt aufgerufen wird, wird der aufrufende Thread (normalerweise der Haupt-Thread) blockiert, bis der Thread oder Prozess, für den join()
aufgerufen wird, die Ausführung beendet hat.
Multiprocessing
Multiprocessing eignet sich für CPU-intensive Aufgaben und kann Multi-Core-Prozessoren voll ausnutzen, wie unten gezeigt:
import multiprocessing import time def worker(name): print(f"Worker {name} starting") time.sleep(2) # Simulate a time - consuming operation print(f"Worker {name} finished") if __name__ == "__main__": processes = [] for i in range(3): p = multiprocessing.Process(target=worker, args=(i,)) processes.append(p) p.start() for p in processes: p.join() print("All workers finished")
Fazit
Zusätzlich zu den oben genannten asynchronen Methoden gibt es in Python noch andere asynchrone Ansätze, wie z. B. die Verwendung von Callback-Funktionen oder Bibliotheken von Drittanbietern wie Gevent. Jede Methode hat ihre eigenen Vor- und Nachteile. Threads eignen sich beispielsweise für E/A-gebundene Aufgaben, sind aber durch den GIL (Global Interpreter Lock) begrenzt; Multiprocessing eignet sich für CPU-intensive Aufgaben, hat aber einen höheren Speicherbedarf; Bibliotheken von Drittanbietern bieten spezielle Funktionen und Optimierungen, können aber die Komplexität des Projekts erhöhen. Im Gegensatz dazu bietet die async/await
-Syntax eine modernere und lesbarere Art der asynchronen Programmierung und ist derzeit die empfohlene Methode für die Behandlung asynchroner Operationen in Python.
Leapcell: Das Beste von Serverless Webhosting
Lassen Sie mich abschließend eine Plattform vorstellen, die sich am besten für die Bereitstellung von Python-Diensten eignet: Leapcell
🚀 Erstellen Sie mit Ihrer Lieblingssprache
Entwickeln Sie mühelos in JavaScript, Python, Go oder Rust.
🌍 Stellen Sie unbegrenzt viele Projekte kostenlos bereit
Zahlen Sie nur für das, was Sie nutzen – keine Anfragen, keine Gebühren.
⚡ Pay-as-You-Go, keine versteckten Kosten
Keine Leerlaufgebühren, nur nahtlose Skalierbarkeit.
📖 Entdecken Sie unsere Dokumentation
🔹 Folgen Sie uns auf Twitter: @LeapcellHQ