Asyncio ermöglicht Entwicklern das problemlose Schreiben asynchroner Programme in Python. Das Modul bietet auch viele Möglichkeiten für asynchrone Aufgaben und bei der Vielzahl an Möglichkeiten, dies zu tun, kann es verwirrend werden, welche davon man verwenden soll.
In diesem Artikel besprechen wir die vielen Möglichkeiten, wie Sie Aufgaben mit Asyncio erstellen und verwalten können.
In Asyncio ist eine Aufgabe ein Objekt, das eine Coroutine umschließt und deren Ausführung innerhalb der Ereignisschleife plant. Einfach ausgedrückt ist eine Aufgabe eine Möglichkeit, eine Coroutine gleichzeitig mit anderen Aufgaben auszuführen. Sobald eine Aufgabe erstellt wurde, wird sie von der Ereignisschleife ausgeführt und bei Bedarf angehalten und fortgesetzt, damit andere Aufgaben ausgeführt werden können.
Jetzt können wir Methoden zum Erstellen und Verwalten von Aufgaben besprechen. Um eine Aufgabe in Python mit asyncio zu erstellen, verwenden Sie zunächst die Methode asyncio.create_task, die die folgenden Argumente akzeptiert:
coro (erforderlich): Das zu planende Coroutine-Objekt. Dies ist die Funktion, die Sie asynchron ausführen möchten.
Name (optional): Ein Name für die Aufgabe, der für Debugging- oder Protokollierungszwecke nützlich sein kann. Sie können diesem Parameter eine Zeichenfolge zuweisen.
Kontext (optional): Eingeführt in Python 3.11, wird dies verwendet, um eine Kontextvariable für die Aufgabe festzulegen und so die aufgabenlokale Speicherung zu ermöglichen. Es ähnelt dem Thread-lokalen Speicher, ist jedoch für asynchrone Aufgaben geeignet.
Hier ist ein Beispiel für die Verwendung von asyncio.create_task:
import asyncio # Define a coroutine async def greet(name): await asyncio.sleep(1) # Simulate an I/O-bound operation print(f"Hello, {name}!") async def main(): # Create tasks task1 = asyncio.create_task(greet("Alice"), name="GreetingAlice") task2 = asyncio.create_task(greet("Bob"), name="GreetingBob") # Check task names print(f"Task 1 name: {task1.get_name()}") print(f"Task 2 name: {task2.get_name()}") # Wait for both tasks to complete await task1 await task2 # Run the main function asyncio.run(main())
Wenn Sie eine Aufgabe erstellen, können Sie viele Methoden ausführen, wie zum Beispiel:
.cancel(): um die Aufgabe abzubrechen.
.add_done_callback(cb): um eine Rückruffunktion hinzuzufügen, die ausgeführt wird, wenn die Aufgabe erledigt ist.
.done(): um zu überprüfen, ob die Aufgabe abgeschlossen ist.
.result(): um das Ergebnis der Aufgabe abzurufen, nachdem sie abgeschlossen ist.
Da wir nun verstanden haben, wie man eine Aufgabe erstellt, sehen wir uns nun an, wie man mit dem Warten auf eine oder mehrere Aufgaben umgeht.
In diesem Abschnitt besprechen wir, wie man bei einer oder mehreren Aufgaben auf den Abschluss einer Aufgabe wartet. Die asynchrone Programmierung basiert auf der Tatsache, dass wir die Ausführung eines Programms fortsetzen können, wenn eine asynchrone Aufgabe ausgeführt wird. Es kann vorkommen, dass Sie den Ablauf besser kontrollieren und sicherstellen möchten, dass Sie ein Ergebnis haben, mit dem Sie arbeiten können, bevor Sie die Ausführung des Programms sicher fortsetzen.
Um auf den Abschluss einer einzelnen Aufgabe zu warten, können Sie asyncio.wait_for verwenden. Es sind zwei Argumente erforderlich:
awaitable (erforderlich): Dies ist die Coroutine, Aufgabe oder Zukunft, auf die Sie warten möchten. Es kann sich um jedes Objekt handeln, auf das gewartet werden kann, etwa ein Coroutine-Funktionsaufruf, eine asyncio.Task oder eine asyncio.Future.
timeout (optional): Dies gibt die maximale Anzahl von Sekunden an, die auf den Abschluss des aw gewartet werden soll. Wenn das Timeout erreicht ist und das Erwartbare noch nicht abgeschlossen ist, löst asyncio.wait_for einen TimeoutError aus. Wenn das Zeitlimit auf „Keine“ eingestellt ist, wartet die Funktion unbegrenzt auf den Abschluss des Wartens.
Hier ist ein Beispiel, wo diese Methode verwendet wird:
import asyncio async def slow_task(): print("Task started...") await asyncio.sleep(5) # Simulating a long-running task print("Task finished!") return "Completed" async def main(): try: # Wait for slow_task to finish within 2 seconds result = await asyncio.wait_for(slow_task(), timeout=2) print(result) except asyncio.TimeoutError: print("The task took too long and was canceled!") asyncio.run(main())
Im obigen Code ist slow_task() eine Coroutine, die eine lang laufende Aufgabe simuliert, indem sie 5 Sekunden lang schläft. Die Zeile asyncio.wait_for(slow_task(), timeout=2) wartet auf den Abschluss der Aufgabe, begrenzt die Wartezeit jedoch auf 2 Sekunden, was zu einer Zeitüberschreitung führt, da die Aufgabe länger dauert. Wenn das Zeitlimit überschritten wird, wird ein TimeoutError ausgelöst, die Aufgabe wird abgebrochen und die Ausnahme wird durch Drucken einer Meldung behandelt, die angibt, dass die Aufgabe zu lange gedauert hat.
Wir können auch darauf warten, dass mehrere oder eine Gruppe von Aufgaben abgeschlossen sind. Dies ist mit asyncio.wait, asyncio.gather oder asyncio.as_completed möglich. Lassen Sie uns jede Methode untersuchen.
Die Methode asyncio.wait wartet auf eine Sammlung von Aufgaben und gibt zwei Sätze zurück: einen für abgeschlossene Aufgaben und einen für ausstehende Aufgaben. Es werden folgende Argumente benötigt:
aws (erforderlich, iterierbar von Awartables): Eine Sammlung von Coroutine-Objekten, Aufgaben oder Futures, auf die Sie warten möchten.
Timeout (Float oder Keine, optional): Die maximale Anzahl an Sekunden, die gewartet werden soll. Wenn nicht angegeben, wartet es auf unbestimmte Zeit.
return_when (konstant, optional): Gibt an, wann asyncio.wait zurückkehren soll. Zu den Optionen gehören:
Let's see how it is used in an example.
import asyncio import random async def task(): await asyncio.sleep(random.uniform(1, 3)) async def main(): tasks = [asyncio.create_task(task()) for _ in range(3)] done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) print(f"Done tasks: {len(done)}, Pending tasks: {len(pending)}") asyncio.run(main())
In the code above, asyncio.wait waits for a group of tasks and returns two sets: one with completed tasks and another with those still pending. You can control when it returns, such as after the first task is completed or after all tasks are done. In the example, asyncio.wait returns when the first task is completed, leaving the rest in the pending set.
The asyncio.gather method runs multiple awaitable objects concurrently and returns a list of their results, optionally handling exceptions. Let's see the arguments it takes.
*aws (required, multiple awaitables): A variable number of awaitable objects (like coroutines, tasks, or futures) to run concurrently.
return_exceptions (bool, optional): If True, exceptions in the tasks will be returned as part of the results list instead of being raised.
Let's see how it can be used in an example.
import asyncio import random async def task(id): await asyncio.sleep(random.uniform(1, 3)) return f"Task {id} done" async def main(): results = await asyncio.gather(task(1), task(2), task(3)) print(results) asyncio.run(main())
In the code above, asyncio.gather runs multiple awaitable objects concurrently and returns a list of their results in the order they were passed in. It allows you to handle exceptions gracefully if return_exceptions is set to True. In the example, three tasks are run simultaneously, and their results are returned in a list once all tasks are complete.
The asyncio.as_completed method is used to return an iterator that yields tasks as they are completed, allowing results to be processed immediately. It takes the following arguments:
aws (iterable of awaitables): A collection of coroutine objects, tasks, or futures.
timeout (float or None, optional): The maximum number of seconds to wait for tasks to complete. If not provided, it waits indefinitely.
import asyncio import random async def task(id): await asyncio.sleep(random.uniform(1, 3)) return f"Task {id} done" async def main(): tasks = [task(i) for i in range(3)] for coro in asyncio.as_completed(tasks): result = await coro print(result) asyncio.run(main())
In the example above, asyncio.as_completed returns an iterator that yields results as each task completes, allowing you to process them immediately. This is useful when you want to handle results as soon as they're available, rather than waiting for all tasks to finish. In the example, the tasks are run simultaneously, and their results are printed as each one finishes, in the order they complete.
So to make a summary, you use:
asyncio.wait: when you need to handle multiple tasks and want to track which tasks are completed and which are still pending. It's useful when you care about the status of each task separately.
asyncio.gather: when you want to run multiple tasks concurrently and need the results in a list, especially when the order of results matters or you need to handle exceptions gracefully.
asyncio.as_completed: when you want to process results as soon as each task finishes, rather than waiting for all tasks to complete. It’s useful for handling results in the order they become available.
However, these methods don't take atomic task management with built-in error handling. In the next section, we will see about asyncio.TaskGroup and how to use it to manage a group of tasks.
asyncio.TaskGroup is a context manager introduced in Python 3.11 that simplifies managing multiple tasks as a group. It ensures that if any task within the group fails, all other tasks are canceled, providing a way to handle complex task management with robust error handling. The class has one method called created_task used to create and add tasks to the task group. You pass a coroutine to this method, and it returns an asyncio.Task object that is managed by the group.
Here is an example of how it is used:
import asyncio async def task1(): await asyncio.sleep(1) return "Task 1 done" async def task2(): await asyncio.sleep(2) return "Task 2 done" async def task_with_error(): await asyncio.sleep(1) raise ValueError("An error occurred") async def main(): try: async with asyncio.TaskGroup() as tg: task1 = tg.create_task(task1()) task2 = tg.create_task(task2()) error_task = tg.create_task(task_with_error()) except Exception as e: print(f"Error: {e}") # Print results from completed tasks print("Task 1 result:", task1.result()) print("Task 2 result:", task2.result()) asyncio.run(main())
asyncio.TaskGroup manages multiple tasks and ensures that if any task fails, all other tasks in the group are canceled. In the example, a task with an error causes the entire group to be canceled, and only the results of completed tasks are printed.
Usage for this can be in web scraping. You can use asyncio.TaskGroup to handle multiple concurrent API requests and ensure that if any request fails, all other requests are canceled to avoid incomplete data.
We are at the end of the article and we have learned the multiple methods asyncio provides to create and manage tasks. Here is a summary of the methods:
asyncio.wait_for: Wait for a task with a timeout.
asyncio.wait: Wait for multiple tasks with flexible completion conditions.
asyncio.gather: Aggregate multiple tasks into a single awaitable.
asyncio.as_completed: Behandeln Sie Aufgaben, sobald sie abgeschlossen sind.
asyncio.TaskGroup: Verwalten Sie eine Gruppe von Aufgaben mit automatischem Abbruch bei Fehler.
Asynchrone Programmierung kann die Art und Weise, wie Sie gleichzeitige Aufgaben in Python bearbeiten, verändern und Ihren Code effizienter und reaktionsschneller machen. In diesem Artikel haben wir durch die verschiedenen Methoden navigiert, die Asyncio zum Erstellen und Verwalten von Aufgaben bietet, von einfachen Zeitüberschreitungen bis hin zu anspruchsvollen Aufgabengruppen. Wenn Sie wissen, wann und wie die einzelnen Methoden – asyncio.wait_for, asyncio.wait, asyncio.gather, asyncio.as_completed und asyncio.TaskGroup – verwendet werden, können Sie das volle Potenzial der asynchronen Programmierung ausschöpfen und Ihre Anwendungen robuster und skalierbarer machen.
Für einen tieferen Einblick in die asynchrone Programmierung und weitere praktische Beispiele lesen Sie hier unseren ausführlichen Leitfaden.
Wenn Ihnen dieser Artikel gefallen hat, denken Sie darüber nach, meinen Newsletter zu abonnieren, damit Sie zukünftige Updates nicht verpassen.
Viel Spaß beim Codieren!
Das obige ist der detaillierte Inhalt vonAufgaben mit Asyncio erstellen und verwalten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!