„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Asynchrone Programmierung mit Asyncio

Asynchrone Programmierung mit Asyncio

Veröffentlicht am 21.08.2024
Durchsuche:145

Asynchronous Programming with Asyncio

In der Programmierwelt ist das Konzept der „Nicht-Blockierung“ allgegenwärtig. JavaScript-Entwickler verwenden häufig den Begriff „asynchron“, da er eine der Stärken von JavaScript darstellt. Um die asynchrone Programmierung wirklich zu verstehen, ist es jedoch wichtig, die Konzepte der gleichzeitigen und parallelen Programmierung zu verstehen.

Gleichzeitige Programmierung

Wenn mehrere unabhängige Einheiten gleichzeitig arbeiten, erfolgt die Programmierung gleichzeitig. Dies bedeutet nicht unbedingt, dass diese Aufgaben genau gleichzeitig ausgeführt werden. Stattdessen bedeutet dies, dass Aufgaben im Laufe der Zeit Fortschritte machen, indem sie Ressourcen, wie z. B. CPU-Zeit, gemeinsam nutzen. Der Hauptvorteil der gleichzeitigen Programmierung ist ihre Robustheit: Wenn ein Prozess abstürzt, funktioniert der Rest Ihres Programms weiterhin.

Parallele Programmierung

Wenn ein Algorithmus seine Arbeit in mehrere Teile aufteilen kann, ist er parallel. Je mehr Prozessoren Sie haben, desto mehr profitieren Sie von der Parallelität. Effiziente Parallelprogrammierung optimiert die Ressourcen moderner Maschinen für eine bessere Leistung.

Veranschaulichung von Parallelität vs. Parallelität beim Kochen

Parallelitätsbeispiel:

Stellen Sie sich vor, Sie bereiten eine Mahlzeit zu, bei der Sie etwas Fleisch grillen und eine Soße zubereiten müssen. Sie beginnen damit, das Fleisch auf den Grill zu legen. Während das Fleisch grillt, hacken Sie die Tomaten und anderes Gemüse für die Soße. Dann fangen Sie an, die Soße zu kochen, während Sie gelegentlich das Fleisch kontrollieren. Hier sind beide Aufgaben (Fleisch grillen und Soße zubereiten) im Gange, aber Sie wechseln Ihre Aufmerksamkeit zwischen ihnen. Dies stellt Parallelität dar.

Parallelitätsbeispiel:

Angenommen, Sie haben einen Freund, der Ihnen hilft. Während Sie sich auf das Grillen des Fleisches konzentrieren, kümmert sich Ihr Freund um die Zubereitung der Soße. Beide Aufgaben werden gleichzeitig erledigt, ohne dass die Aufmerksamkeit zwischen ihnen gewechselt werden muss. Dies stellt Parallelität dar.

Was ist asynchrone Programmierung?

Asynchrone Programmierung umfasst die Verarbeitung von Eingabe-/Ausgabeoperationen (E/A), die außerhalb Ihres Programms stattfinden, wie z. B. Benutzereingaben, Drucken auf einem Terminal, Lesen von einem Socket oder Schreiben auf die Festplatte. Die Hauptmerkmale asynchroner E/A sind:

  • Die für den Vorgang benötigte Zeit ist nicht CPU-abhängig. Stattdessen hängt es von Faktoren wie Festplattengeschwindigkeit, Netzwerklatenz und anderen externen Bedingungen ab.

  • Das Programm kann nicht vorhersagen, wann der Vorgang enden wird.

Bei Diensten mit erheblichen E/A-Vorgängen (wie Webservern, Datenbanken und Bereitstellungsskripts) kann die Optimierung dieser Vorgänge die Leistung erheblich verbessern.

Sehen wir uns Beispiele für blockierenden und nicht blockierenden Code an.

Beispiel für blockierenden und nicht blockierenden Code

Stellen Sie sich ein einfaches Programm vor:

import time

def task():
    time.sleep(2)
    print("Hello")

for _ in range(3):
    task()

In diesem synchronen Programm wartet jede Aufgabe auf den Abschluss der vorherigen, was zu Verzögerungen führt.

Sehen wir uns nun eine asynchrone Version mit asyncio an:

import asyncio

async def task():
    await asyncio.sleep(2)
    print("Hello")

async def main():
    tasks = [task() for _ in range(3)]
    await asyncio.gather(*tasks)

asyncio.run(main())

In diesem asynchronen Programm werden Aufgaben gleichzeitig ausgeführt, wodurch die Gesamtausführungszeit verkürzt wird. Lassen Sie uns die Komponenten der asynchronen Programmierung erkunden.

Komponenten der asynchronen Programmierung

Ereignisschleifen, Coroutinen und Futures sind die wesentlichen Elemente eines asynchronen Python-Programms.

  • Ereignisschleife: Verwaltet den Aufgabenwechsel und den Ausführungsfluss und verfolgt die Aufgaben, die asynchron ausgeführt werden sollen.

  • Koroutinen: Spezielle Funktionen, die angehalten und fortgesetzt werden können, sodass andere Aufgaben während des Wartens ausgeführt werden können. Eine Coroutine gibt an, wo in der Funktion das Taskwechselereignis stattfinden soll, und gibt die Kontrolle an die Ereignisschleife zurück. Coroutinen werden normalerweise von der Ereignisschleife erstellt und intern in einer Aufgabenwarteschlange gespeichert.

  • Futures: Platzhalter für Ergebnisse von Coroutinen, die das Ergebnis oder Ausnahmen speichern. Sobald die Ereignisschleife eine Coroutine initiiert, wird eine entsprechende Zukunft erstellt, die das Ergebnis der Coroutine oder eine Ausnahme speichert, falls während der Ausführung der Coroutine eine ausgelöst wurde.

Nachdem wir die entscheidenden Teile der asynchronen Programmierung in Python erklärt haben, schreiben wir etwas Code.

Asynchronen Code schreiben

Da Sie nun das asynchrone Programmiermuster verstanden haben, schreiben wir ein kleines Skript und analysieren die Ausführung. Hier ist ein einfaches asynchrones Skript:

import asyncio

async def task():
    await asyncio.sleep(2)
    print("Hello")

async def main():
    tasks = [task() for _ in range(3)]
    await asyncio.gather(*tasks)

asyncio.run(main())

Im obigen Code versuchen wir, die Ausführung anderer Aufgaben fortzusetzen, auch wenn eine andere Ausführung schläft (blockiert). Beachten Sie das Schlüsselwort async vor der Aufgabe und den Hauptfunktionen.

Diese Funktionen sind jetzt Coroutinen.

Coroutinen-Funktionen in Python wird das Schlüsselwort async vorangestellt. Die Funktion main() ist hier der Aufgabenkoordinator oder unsere einzelne Ereignisschleife, da sie alle Aufgaben mit der Methode async.gather ausführt. Die Funktion asyncio.gather führt gleichzeitig erwartbare Objekte aus.

Ausgabe:

Hello
Hello
Hello
Program executed in 2.01 seconds.

Wenn jede Aufgabe „await asyncio.sleep(2)“ erreicht, geht sie einfach zur nächsten Aufgabe über und kommt zurück, wenn sie fertig ist. Es ist, als würde man sagen: „Ich gehe zwei Sekunden schlafen. Mach etwas anderes.“

Sehen wir uns für einen schnellen Vergleich die synchrone Version an.

import time

def task():
    time.sleep(2)
    print("Hello")

for _ in range(3):
    task()

Im obigen Code gehen wir den traditionellen Programmierweg in Python ein. Sie werden feststellen, dass die Ausführung des Prozesses deutlich mehr Zeit in Anspruch nehmen wird.

Ausgabe:

Hello
Hello
Hello
Program executed in 6.01 seconds.

Jetzt können Sie die Ausführungszeit erkennen. Stellen Sie sich time.sleep() als blockierende Aufgabe und asyncio.sleep() als nicht blockierende oder lange Aufgabe vor. Bei der asynchronen Programmierung besteht der Vorteil des Wartens auf etwas wie asyncio.sleep() darin, dass die umgebende Funktion vorübergehend die Kontrolle an eine andere Funktion abgeben kann, die sofort zur Ausführung bereit ist.

Nachdem wir einige grundlegende Beispiele der asynchronen Programmierung in Python verstanden haben, erkunden wir nun die Regeln der asynchronen Programmierung in Python.

Regeln der Asyncio-Programmierung

  1. Coroutinen: Coroutinen können nicht direkt ausgeführt werden. Wenn Sie versuchen, eine Coroutine-Funktion direkt auszuführen, gibt sie ein Coroutine-Objekt zurück. Verwenden Sie stattdessen asyncio.run():

    import asyncio
    
    async def hello():
        await asyncio.sleep(1)
        print('Hello')
    
    asyncio.run(hello())
    
  2. Erwartbare Objekte: Coroutinen, Futures und Aufgaben sind die wichtigsten erwartbaren Objekte. Python-Coroutinen sind „erwartbar“ und können von anderen Coroutinen erwartet werden.

  3. Await-Schlüsselwort:await kann nur innerhalb asynchroner Funktionen verwendet werden.

    async def hello():
        await asyncio.sleep(1)
        print("Hello")
    
  4. Kompatibilität: Nicht alle Python-Module sind mit der asynchronen Programmierung kompatibel. Wenn Sie beispielsweise „await asyncio.sleep()“ durch „time.sleep()“ ersetzen, wird ein Fehler verursacht. Die Liste der kompatiblen und gewarteten Module können Sie hier einsehen.

Im nächsten Abschnitt werden wir eine häufige Verwendung der asynchronen Programmierung, HTTP-Anfragen, untersuchen.

Programmbeispiel: Asynchrone Anfragen

Sehen wir uns den folgenden Code an:

import aiohttp
import asyncio

async def fetch(session, city):
    url = f"https://www.prevision-meteo.ch/services/json/{city}"
    async with session.get(url) as response:
        data = await response.json()
        print(f"Temperature at {city}: {data['current_condition']['tmp']} C")

async def main():
    async with aiohttp.ClientSession() as session:
        cities = ['paris', 'toulouse', 'marseille']
        tasks = [fetch(session, city) for city in cities]
        await asyncio.gather(*tasks)

asyncio.run(main())

Im obigen Code erstellen wir zwei asynchrone Funktionen: eine zum Abrufen von Daten von der prevision-meteo-URL und eine Hauptfunktion zum Ausführen der Prozesse im Python-Code. Das Ziel besteht darin, asynchrone HTTP-GET-Anfragen zu senden, um Temperaturen abzurufen und die Antworten auszudrucken.

In den Haupt- und Abruffunktionen verwenden wir async with. In der Abruffunktion stellt async with sicher, dass die Verbindung ordnungsgemäß geschlossen wird. In der Hauptfunktion sorgt es dafür, dass die ClientSession nach Abschluss der Anfragen geschlossen wird. Diese Praktiken sind beim asynchronen Codieren in Python wichtig, um Ressourcen effizient zu verwalten und Lecks zu verhindern.

In der letzten Zeile der Hauptfunktion verwenden wir waiting asyncio.gather(*tasks). In unserem Fall werden alle Aufgaben gleichzeitig ausgeführt, sodass das Programm mehrere HTTP-Anfragen gleichzeitig senden kann. Durch die Verwendung von „await“ wird sichergestellt, dass das Programm auf den Abschluss aller Aufgaben wartet, bevor es fortfährt.

Ausgabe:

Temperature at marseille: 25 C
Temperature at toulouse: 24 C
Temperature at paris: 18 C
Program executed in 5.86 seconds.

Synchrone Version zum Vergleich

Code:

import requests
import time

def fetch(city):
    url = f"https://www.prevision-meteo.ch/services/json/{city}"
    response = requests.get(url)
    data = response.json()
    print(f"Temperature at {city}: {data['current_condition']['tmp']} C")

def main():
    cities = ['paris', 'toulouse', 'marseille']
    for city in cities:
        fetch(city)

start_time = time.time()
main()
print(f"Program executed in {time.time() - start_time:.2f} seconds.")

Ausgabe:

Temperature at Paris: 18 C
Temperature at Toulouse: 24 C
Temperature at Marseille: 25 C
Program executed in 9.01 seconds.

Wann sollte asynchrone Programmierung verwendet werden?

Das asynchrone Modell bietet die beste Leistung, wenn:

  • Es gibt eine große Anzahl an Aufgaben, so dass immer mindestens eine Aufgabe voranschreiten kann.

  • Aufgaben erfordern erhebliche E/A-Vorgänge, was dazu führt, dass ein asynchrones Programm viel Zeit damit verschwendet, zu blockieren, wenn andere Aufgaben ausgeführt werden könnten.

  • Aufgaben sind weitgehend unabhängig, wodurch die Kommunikation zwischen Aufgaben minimiert wird (und somit das Warten einer Aufgabe auf eine andere).

Abschluss

In diesem Tutorial haben wir Folgendes behandelt:

  • Die Konzepte der asynchronen Programmierung und verwandte Konzepte.

  • Effektive Nutzung von async/await.

  • Asynchrone HTTP-Anfragen mit aiohttp erstellen.

  • Die Vorteile der asynchronen Programmierung.

Danke fürs Lesen. Der zweite Teil befasst sich mit der asynchronen Programmierung mit Django.

Ressourcen

  • Python-Dokumentation: Coroutinen und Aufgaben

  • Python-Dokumentation: asyncio – Asynchrone E/A

  • aiohttp-Dokumentation

  • Aio-Bibliotheken

  • Parallelität vs. Parallelität

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/koladev/asynchronous-programming-with-asyncio-3ad1?1 Bei Verstößen wenden Sie sich bitte an [email protected], um ihn zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3