Parallelitätsprogrammierung ist ein Programmieransatz, der sich mit der gleichzeitigen Ausführung mehrerer Aufgaben befasst. In Python ist asyncio ein leistungsstarkes Tool zur Implementierung asynchroner Programmierung. Basierend auf dem Konzept von Coroutinen kann Asyncio E/A-intensive Aufgaben effizient bewältigen. In diesem Artikel werden die Grundprinzipien und die Verwendung von Asyncio vorgestellt.
Wir wissen, dass die Verwendung von Multithreading bei der Verarbeitung von E/A-Vorgängen die Effizienz im Vergleich zu einem normalen Einzelthread erheblich verbessern kann. Warum brauchen wir also immer noch Asyncio?
Multithreading hat viele Vorteile und ist weit verbreitet, weist aber auch gewisse Einschränkungen auf:
Genau um diese Probleme zu lösen, ist Asyncio entstanden.
Unterscheiden wir zunächst zwischen den Konzepten Sync (synchron) und Async (asynchron).
Zusammenfassend basiert das Funktionsprinzip von Asyncio auf den Mechanismen von Coroutinen und Ereignisschleifen. Durch die Verwendung von Coroutinen für asynchrone Operationen und die Verantwortung für die Planung und Ausführung von Coroutinen durch die Ereignisschleife realisiert Asyncio ein effizientes asynchrones Programmiermodell.
Coroutinen sind ein wichtiges Konzept in Asyncio. Es handelt sich um leichtgewichtige Ausführungseinheiten, die schnell zwischen Aufgaben wechseln können, ohne dass der Aufwand für den Thread-Wechsel anfällt. Coroutinen können mit dem Schlüsselwort „async“ definiert werden. Das Schlüsselwort „await“ wird verwendet, um die Ausführung der Coroutine anzuhalten und nach Abschluss eines bestimmten Vorgangs fortzusetzen.
Hier ist ein einfacher Beispielcode, der zeigt, wie Coroutinen für die asynchrone Programmierung verwendet werden:
import asyncio async def hello(): print("Hello") await asyncio.sleep(1) # Simulate a time-consuming operation print("World") # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(hello())
In diesem Beispiel ist die Funktion hello() eine Coroutine, die mit dem Schlüsselwort async definiert ist. Innerhalb der Coroutine können wir „await“ verwenden, um ihre Ausführung anzuhalten. Hier wird asyncio.sleep(1) verwendet, um einen zeitaufwändigen Vorgang zu simulieren. Die Methode run_until_complete() fügt die Coroutine zur Ereignisschleife hinzu und führt sie aus.
asyncio wird hauptsächlich zur Verarbeitung von E/A-intensiven Aufgaben wie Netzwerkanforderungen, Lesen und Schreiben von Dateien verwendet. Es bietet eine Reihe von APIs für asynchrone E/A-Vorgänge, die in Kombination mit dem Schlüsselwort „await“ verwendet werden können, um auf einfache Weise eine asynchrone Programmierung zu erreichen.
Hier ist ein einfacher Beispielcode, der zeigt, wie man Asyncio für asynchrone Netzwerkanfragen verwendet:
import asyncio import aiohttp async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: html = await fetch(session, 'https://www.example.com') print(html) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
In diesem Beispiel verwenden wir die aiohttp-Bibliothek für Netzwerkanfragen. Die Funktion fetch() ist eine Coroutine. Es initiiert eine asynchrone GET-Anfrage über die Methode session.get() und wartet mit dem Schlüsselwort „await“ auf die Rückgabe der Antwort. Die Funktion main() ist eine weitere Coroutine. Es erstellt darin ein ClientSession-Objekt zur Wiederverwendung und ruft dann die Methode fetch() auf, um den Inhalt der Webseite abzurufen und auszudrucken.
Hinweis: Hier verwenden wir aiohttp anstelle der Requests-Bibliothek, da die Requests-Bibliothek nicht mit asyncio kompatibel ist, die aiohttp-Bibliothek hingegen schon. Um Asyncio sinnvoll nutzen zu können, insbesondere um seine leistungsstarken Funktionen auszuschöpfen, sind in vielen Fällen entsprechende Python-Bibliotheken erforderlich.
asyncio bietet auch einige Mechanismen zum gleichzeitigen Ausführen mehrerer Aufgaben, wie z. B. asyncio.gather() und asyncio.wait(). Das Folgende ist ein Beispielcode, der zeigt, wie diese Mechanismen verwendet werden, um mehrere Coroutine-Aufgaben gleichzeitig auszuführen:
import asyncio async def task1(): print("Task 1 started") await asyncio.sleep(1) print("Task 1 finished") async def task2(): print("Task 2 started") await asyncio.sleep(2) print("Task 2 finished") async def main(): await asyncio.gather(task1(), task2()) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
In diesem Beispiel definieren wir zwei Coroutine-Aufgaben task1() und task2(), die beide einige zeitaufwändige Vorgänge ausführen. Die Coroutine main() startet diese beiden Aufgaben gleichzeitig über asyncio.gather() und wartet auf deren Abschluss. Die gleichzeitige Ausführung kann die Effizienz der Programmausführung verbessern.
Sollten wir in tatsächlichen Projekten Multithreading oder Asyncio wählen? Ein Big Shot hat es anschaulich zusammengefasst:
import asyncio async def hello(): print("Hello") await asyncio.sleep(1) # Simulate a time-consuming operation print("World") # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(hello())
Geben Sie eine Liste ein. Für jedes Element in der Liste möchten wir die Summe der Quadrate aller ganzen Zahlen von 0 bis zu diesem Element berechnen.
import asyncio import aiohttp async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: html = await fetch(session, 'https://www.example.com') print(html) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
Die Ausführungszeit beträgt 16,00943413000002 Sekunden
import asyncio async def task1(): print("Task 1 started") await asyncio.sleep(1) print("Task 1 finished") async def task2(): print("Task 2 started") await asyncio.sleep(2) print("Task 2 finished") async def main(): await asyncio.gather(task1(), task2()) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
Die Ausführungszeit beträgt 7,314132894999999 Sekunden
In diesem verbesserten Code verwenden wir concurrent.futures.ProcessPoolExecutor, um einen Prozesspool zu erstellen, und verwenden dann die Methode executor.map(), um Aufgaben zu übermitteln und Ergebnisse zu erhalten. Beachten Sie, dass Sie nach der Verwendung von executor.map(), wenn Sie die Ergebnisse benötigen, die Ergebnisse in einer Liste iterieren oder andere Methoden verwenden können, um die Ergebnisse zu verarbeiten.
if io_bound: if io_slow: print('Use Asyncio') else: print('Use multi-threading') elif cpu_bound: print('Use multi-processing')
Die Ausführungszeit beträgt 5,024221667 Sekunden
concurrent.futures.ProcessPoolExecutor und multiprocessing sind beide Bibliotheken zur Implementierung der Parallelität mehrerer Prozesse in Python. Es gibt einige Unterschiede:
Zusammenfassend ist concurrent.futures.ProcessPoolExecutor eine High-Level-Schnittstelle, die die zugrunde liegenden Multiprozessfunktionen kapselt und für die einfache Parallelisierung von Multiprozessaufgaben geeignet ist. Multiprocessing ist eine Bibliothek auf niedrigerer Ebene, die mehr Kontrolle und Flexibilität bietet und für Szenarien geeignet ist, die eine feinkörnige Steuerung von Prozessen erfordern. Sie müssen die geeignete Bibliothek entsprechend den spezifischen Anforderungen auswählen. Wenn es sich nur um eine einfache Aufgabenparallelisierung handelt, können Sie concurrent.futures.ProcessPoolExecutor verwenden, um den Code zu vereinfachen. Wenn mehr Steuerung und Kommunikation auf niedriger Ebene erforderlich sind, können Sie die Multiprocessing-Bibliothek verwenden.
Im Gegensatz zu Multithreading ist Asyncio Single-Threading, aber der Mechanismus seiner internen Ereignisschleife ermöglicht die gleichzeitige Ausführung mehrerer verschiedener Aufgaben und verfügt über eine größere autonome Kontrolle als Multithreading.
Asyncio-Aufgaben werden während des Betriebs nicht unterbrochen, sodass keine Race-Condition-Situation auftritt.
Besonders in Szenarien mit starken E/A-Vorgängen bietet Asyncio eine höhere Betriebseffizienz als Multithreading. Denn die Kosten für den Aufgabenwechsel in Asyncio sind viel geringer als die für Threadwechsel und die Anzahl der Aufgaben, die Asyncio starten kann, ist viel größer als die Anzahl der Threads im Multithreading.
Es ist jedoch zu beachten, dass die Verwendung von Asyncio in vielen Fällen die Unterstützung bestimmter Bibliotheken von Drittanbietern erfordert, wie z. B. aiohttp im vorherigen Beispiel. Und wenn die E/A-Vorgänge schnell und nicht schwer sind, kann die Verwendung von Multithreading das Problem ebenfalls effektiv lösen.
Lassen Sie mich abschließend die ideale Plattform für die Bereitstellung von Flask/FastAPI vorstellen: Leapcell.
Leapcell ist eine Cloud-Computing-Plattform, die speziell für moderne verteilte Anwendungen entwickelt wurde. Das Pay-as-you-go-Preismodell stellt sicher, dass keine Leerlaufkosten anfallen, d. h. Benutzer zahlen nur für die Ressourcen, die sie tatsächlich nutzen.
Erfahren Sie mehr in der Dokumentation!
Leapcell Twitter: https://x.com/LeapcellHQ
Das obige ist der detaillierte Inhalt vonHochleistungs-Python: Asyncio. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!