Computerhaus Quickborn

Asyncio-Tutorial: Effizienteres Python schreiben​

srcset="https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?quality=50&strip=all 3458w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=300%2C168&quality=50&strip=all 300w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=768%2C432&quality=50&strip=all 768w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1024%2C576&quality=50&strip=all 1024w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1536%2C864&quality=50&strip=all 1536w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=2048%2C1152&quality=50&strip=all 2048w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1240%2C697&quality=50&strip=all 1240w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=150%2C84&quality=50&strip=all 150w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=854%2C480&quality=50&strip=all 854w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=640%2C360&quality=50&strip=all 640w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=444%2C250&quality=50&strip=all 444w" width="1024" height="576" sizes="(max-width: 1024px) 100vw, 1024px">Die Python-Bibliothek asyncio unterstützt bei asynchronen Python-Tasks. Lesen Sie, wie’s geht.MagicMore | shutterstock.com Python-Programme zu schreiben, die nicht auf unabhängige Tasks warten müssen, wird mit der asynchronen Programmierfunktionalität – oder kürzer (und schöner) Async – möglich. Mit der asyncio-Bibliothek ist ein Toolset in Python integriert, um Disk- oder Network-I/O asynchron zu verarbeiten.    Zu diesem Zweck stellt asyncio zweierlei Arten von APIs zur Verfügung: High-Level-APIs sind besonders nützlich und auf die unterschiedlichsten Applikationen anwendbar. Low-Level-APIs sind besonders leistungsstark, aber auch komplex und kommen deswegen seltener zum Einsatz. In diesem Artikel werfen wir einen Blick auf die gängigsten High-Level-APIs von asyncio und erörtern anhand einiger Beispiele, wie Sie diese für asynchrone Python-Tasks einsetzen können. Abschließend gibt‘s auch noch einige Low(er)-Level-Async-Tipps. Coroutines und Tasks mit asyncio Naturgemäß dürfte asyncio am häufigsten zum Einsatz kommen, um die asynchronen Teile Ihres Python-Skripts auszuführen. Dazu sollten Sie wissen, wie Sie mit Coroutines und Tasks umgehen. Beides gehört zu den Async-Komponenten von Python. Diese können ausschließlich miteinander genutzt werden – nicht mit konventionellem, synchronen Python-Code. Um diesen „Gap“ zu überbrücken, kommt asyncio zum Einsatz. Vorausgesetzt, Sie nutzen die asyncio.run-Funktion: import asyncio async def main(): print ("Waiting 5 seconds. ") for _ in range(5): await asyncio.sleep(1) print (".") print ("Finished waiting.") asyncio.run(main()) Sie bewirkt, dass main() – inklusive sämtlicher Coroutines, die es auslöst – ausgeführt wird. Allgemein gilt: Ein Python-Programm sollte nur ein einziges .run()-Statement aufweisen – ebenso wie es nur eine main()-Funktion enthalten sollte. Wird Async nicht mit der nötigen Sorgfalt verwendet, kann es den Control Flow eines Programms schwer lesbar machen. Mit einem Einstiegspunkt in den Async-Code Programms bleibt alles übersichtlich. Async-Funktionen können auch als Tasks, beziehungsweise Objekte, die Coroutines umschließen, geplant werden. async def my_task(): do_something() task = asyncio.create_task(my_task()) Dadurch wird my_task() im Event Loop ausgeführt, die Ergebnisse in task gespeichert. Tasks sind vor allem dann nützlich, wenn Sie etwas einrichten möchten, das zunächst im Hintergrund laufen und zu einem späteren Zeitpunkt Ergebnisse liefern soll. Ein Task könnte beispielsweise in einer Liste gespeichert werden, wo sich die Ergebnisse anschließend überprüfen lassen – entweder zu einem geplanten Zeitpunkt oder on demand.   Wenn Sie nur einen Task haben, von dem Sie Ergebnisse erwarten, können Sie mit asyncio.wait_for(task) darauf warten, dass dieser beendet wird und mit task.result() das Ergebnis abrufen. Wenn Sie damit planen, mehrere Tasks auszuführen und warten möchten, bis alle abgeschlossen sind, nutzen Sie asyncio.wait([task1, task2]), um die Ergebnisse zu sammeln. Sie können auch einen Timeout für die Operationen setzen, wenn Sie einen bestimmten Zeitrahmen nicht sprengen sollen. Event Loop mit asyncio managen Beim Event Loop handelt es sich um ein Objekt, das Async-Funktionen und -Callbacks ausführt. Es wird automatisch erstellt, sobald Sie die asyncio.run()-Funktion nutzen. Um die Übersicht zu wahren, empfiehlt es sich, nur einen asynchronen Event Loop pro Programm zu verwenden. Falls Sie fortgeschrittenere Software schreiben möchten, etwa die für einen Server, brauchen Sie Lower-Level-Zugang zum Event Loop. Dazu arbeiten Sie am besten direkt mit seinen internen Komponenten. Für einfache Aufgaben ist das nicht erforderlich. Daten über asyncio mit Streams lesen und schreiben Langlaufende Netzwerk-Prozesse sind für Async ein ideales Szenario. Hierbei könnte die Applikation blockiert werden, weil sie darauf wartet, dass eine andere Ressource Ergebnisse zurückgibt. Um dieses Problem zu beheben, bietet asyncio sogenannte Streams. Dabei handelt es sich um High-Level-Mechanismen, die für Network-I/O-Aufgaben zum Einsatz kommen. In diesem Zuge fungieren sie auch als Server für Netzwerk-Requests.   Für Netzwerk-Read- und -Write-Vorgänge auf hoher Ebene nutzt asyncio zwei Klassen: StreamReader und StreamWriter. Wenn Sie einen Netzwerk-Read-Vorgang starten wollen, nutzen Sie asyncio.open_connection(), um die Verbindung herzustellen. Diese Funktion gibt ein Tupel von StreamReader– und StreamWriter-Objekten zurück. Für die Kommunikation kommen jeweils die Methoden .read() und .write() zum Einsatz. Um Verbindungen von Remote-Hosts zu empfangen, nutzen Sie asyncio.start_server(). Die Funktion nutzt client_connected_cb als Callback-Funktion, die immer dann aufgerufen wird, wenn sie eine Anfrage erhält. Die Callback-Funktion nimmt Instanzen von StreamReader und StreamWriter als Argumente, sodass Sie die Read/Write-Logik für den Server verarbeiten können. (hier ein simples Beispiel für einen HTTP-Server, der die asyncio-gesteuerte aiohttp-Bibliothek verwendet.) Tasks synchronisieren mit asyncio Asynchrone Tasks werden in der Regel isoliert ausgeführt, sollen manchmal aber miteinander kommunizieren. Um zwischen Tasks zu synchronisieren, bietet asyncio mehrere Mechanismen: Queues: Warteschlangen ermöglichen es asynchronen Funktionen, Python-Objekte in einer Reihe anzuordnen, die von anderen Async-Funktionen verarbeitet werden können – zum Beispiel, um Workloads basierend auf ihrem Verhalten auf verschiedene Funktionen zu verteilen. Synchronization Primitives: Locks, Events, Conditions und Semaphores funktionieren in asyncio genauso wie ihre konventionellen Python-Gegenstücke. Sie sind darauf konzipiert, andere Arten von Aktivitäten zwischen Tasks zu koordinieren – beispielsweise, um auf eine Ressource zuzugreifen, die jeweils nur von einer Entität genutzt werden kann. Zu beachten ist, dass keine dieser Methoden Thread-Safe ist. Das ist kein Problem für Async-Tasks, die im selben Event Loop ausgeführt werden. Um Informationen mit Tasks in anderen Event Loops, Betriebssystem-Threads oder Prozessen zu teilen, sind Sie auf das Threading- Modul und seine Objekte angewiesen. Falls Sie Coroutines über Thread-Grenzen hinweg starten möchten, nutzen Sie die Funktion asyncio.run_coroutine_threadsafe() – und übergeben den zu verwendenden Event Loop als Parameter. Coroutines pausieren mit asyncio Über eine willkürliche Zeitspanne innerhalb einer Koroutine zu verharren, ist ein weiterer häufiger asyncio-Anwendungsfall, der eher selten diskutiert wird. Da Sie time.sleep() zu diesem Zweck nicht verwenden können (außer Sie wollen riskieren, das gesamte Programm zu blockieren), nutzen Sie stattdessen asyncio.sleep(). Das gewährleistet, dass andere Coroutines weiter ausgeführt werden können. Sollten Sie im Sinn haben, asyncio.sleep() in einem Loop zu verwenden:  Das ist theoretisch möglich, aber nicht empfehlenswert. Ein asyncio.Event-Objekt zu übergeben, ist der bessere Ansatz, da Sie einfach darauf warten können, dass dieses geändert wird. Async und File I/O in asyncio Standardmäßig blockiert lokaler File I/O den aktuellen Thread. Eine Möglichkeit, das Problem zu umgehen: Delegieren Sie den Vorgang mithilfe von asyncio.to_thread() an einen anderen Thread. So können andere Tasks weiterhin im Event Loop verarbeitet werden.   Eine andere Möglichkeit, File I/O asynchron zu verarbeiten, bietet die Drittanbieter-Bibliothek aiofiles. Sie enthält High-Level-Async-Konstrukte, um Dateien zu öffnen, zu lesen und zu schreiben. Low-Level-Async mit asyncio nutzen Falls Ihre Python-App Lower-Level-Komponenten von asyncio benötigt, stehen die Chancen gut, dass bereits eine entsprechende Async-Python-Bibliothek vorhanden ist, die genau das tut, was Sie brauchen – wie etwa asyncSSH für asynchrone SSH-Sitzungen. Die Awesome-Asnycio-Liste auf GitHub hält zahlreiche Inspirationen bereit. (fm) Sie wollen weitere interessante Beiträge zu diversen Themen aus der IT-Welt lesen? Unsere kostenlosen Newsletter liefern Ihnen alles, was IT-Profis wissen sollten – direkt in Ihre Inbox! 

Asyncio-Tutorial: Effizienteres Python schreiben​ srcset="https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?quality=50&strip=all 3458w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=300%2C168&quality=50&strip=all 300w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=768%2C432&quality=50&strip=all 768w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1024%2C576&quality=50&strip=all 1024w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1536%2C864&quality=50&strip=all 1536w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=2048%2C1152&quality=50&strip=all 2048w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1240%2C697&quality=50&strip=all 1240w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=150%2C84&quality=50&strip=all 150w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=854%2C480&quality=50&strip=all 854w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=640%2C360&quality=50&strip=all 640w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=444%2C250&quality=50&strip=all 444w" width="1024" height="576" sizes="(max-width: 1024px) 100vw, 1024px">Die Python-Bibliothek asyncio unterstützt bei asynchronen Python-Tasks. Lesen Sie, wie’s geht.MagicMore | shutterstock.com Python-Programme zu schreiben, die nicht auf unabhängige Tasks warten müssen, wird mit der asynchronen Programmierfunktionalität – oder kürzer (und schöner) Async – möglich. Mit der asyncio-Bibliothek ist ein Toolset in Python integriert, um Disk- oder Network-I/O asynchron zu verarbeiten.    Zu diesem Zweck stellt asyncio zweierlei Arten von APIs zur Verfügung: High-Level-APIs sind besonders nützlich und auf die unterschiedlichsten Applikationen anwendbar. Low-Level-APIs sind besonders leistungsstark, aber auch komplex und kommen deswegen seltener zum Einsatz. In diesem Artikel werfen wir einen Blick auf die gängigsten High-Level-APIs von asyncio und erörtern anhand einiger Beispiele, wie Sie diese für asynchrone Python-Tasks einsetzen können. Abschließend gibt‘s auch noch einige Low(er)-Level-Async-Tipps. Coroutines und Tasks mit asyncio Naturgemäß dürfte asyncio am häufigsten zum Einsatz kommen, um die asynchronen Teile Ihres Python-Skripts auszuführen. Dazu sollten Sie wissen, wie Sie mit Coroutines und Tasks umgehen. Beides gehört zu den Async-Komponenten von Python. Diese können ausschließlich miteinander genutzt werden – nicht mit konventionellem, synchronen Python-Code. Um diesen „Gap“ zu überbrücken, kommt asyncio zum Einsatz. Vorausgesetzt, Sie nutzen die asyncio.run-Funktion: import asyncio async def main(): print ("Waiting 5 seconds. ") for _ in range(5): await asyncio.sleep(1) print (".") print ("Finished waiting.") asyncio.run(main()) Sie bewirkt, dass main() – inklusive sämtlicher Coroutines, die es auslöst – ausgeführt wird. Allgemein gilt: Ein Python-Programm sollte nur ein einziges .run()-Statement aufweisen – ebenso wie es nur eine main()-Funktion enthalten sollte. Wird Async nicht mit der nötigen Sorgfalt verwendet, kann es den Control Flow eines Programms schwer lesbar machen. Mit einem Einstiegspunkt in den Async-Code Programms bleibt alles übersichtlich. Async-Funktionen können auch als Tasks, beziehungsweise Objekte, die Coroutines umschließen, geplant werden. async def my_task(): do_something() task = asyncio.create_task(my_task()) Dadurch wird my_task() im Event Loop ausgeführt, die Ergebnisse in task gespeichert. Tasks sind vor allem dann nützlich, wenn Sie etwas einrichten möchten, das zunächst im Hintergrund laufen und zu einem späteren Zeitpunkt Ergebnisse liefern soll. Ein Task könnte beispielsweise in einer Liste gespeichert werden, wo sich die Ergebnisse anschließend überprüfen lassen – entweder zu einem geplanten Zeitpunkt oder on demand.   Wenn Sie nur einen Task haben, von dem Sie Ergebnisse erwarten, können Sie mit asyncio.wait_for(task) darauf warten, dass dieser beendet wird und mit task.result() das Ergebnis abrufen. Wenn Sie damit planen, mehrere Tasks auszuführen und warten möchten, bis alle abgeschlossen sind, nutzen Sie asyncio.wait([task1, task2]), um die Ergebnisse zu sammeln. Sie können auch einen Timeout für die Operationen setzen, wenn Sie einen bestimmten Zeitrahmen nicht sprengen sollen. Event Loop mit asyncio managen Beim Event Loop handelt es sich um ein Objekt, das Async-Funktionen und -Callbacks ausführt. Es wird automatisch erstellt, sobald Sie die asyncio.run()-Funktion nutzen. Um die Übersicht zu wahren, empfiehlt es sich, nur einen asynchronen Event Loop pro Programm zu verwenden. Falls Sie fortgeschrittenere Software schreiben möchten, etwa die für einen Server, brauchen Sie Lower-Level-Zugang zum Event Loop. Dazu arbeiten Sie am besten direkt mit seinen internen Komponenten. Für einfache Aufgaben ist das nicht erforderlich. Daten über asyncio mit Streams lesen und schreiben Langlaufende Netzwerk-Prozesse sind für Async ein ideales Szenario. Hierbei könnte die Applikation blockiert werden, weil sie darauf wartet, dass eine andere Ressource Ergebnisse zurückgibt. Um dieses Problem zu beheben, bietet asyncio sogenannte Streams. Dabei handelt es sich um High-Level-Mechanismen, die für Network-I/O-Aufgaben zum Einsatz kommen. In diesem Zuge fungieren sie auch als Server für Netzwerk-Requests.   Für Netzwerk-Read- und -Write-Vorgänge auf hoher Ebene nutzt asyncio zwei Klassen: StreamReader und StreamWriter. Wenn Sie einen Netzwerk-Read-Vorgang starten wollen, nutzen Sie asyncio.open_connection(), um die Verbindung herzustellen. Diese Funktion gibt ein Tupel von StreamReader– und StreamWriter-Objekten zurück. Für die Kommunikation kommen jeweils die Methoden .read() und .write() zum Einsatz. Um Verbindungen von Remote-Hosts zu empfangen, nutzen Sie asyncio.start_server(). Die Funktion nutzt client_connected_cb als Callback-Funktion, die immer dann aufgerufen wird, wenn sie eine Anfrage erhält. Die Callback-Funktion nimmt Instanzen von StreamReader und StreamWriter als Argumente, sodass Sie die Read/Write-Logik für den Server verarbeiten können. (hier ein simples Beispiel für einen HTTP-Server, der die asyncio-gesteuerte aiohttp-Bibliothek verwendet.) Tasks synchronisieren mit asyncio Asynchrone Tasks werden in der Regel isoliert ausgeführt, sollen manchmal aber miteinander kommunizieren. Um zwischen Tasks zu synchronisieren, bietet asyncio mehrere Mechanismen: Queues: Warteschlangen ermöglichen es asynchronen Funktionen, Python-Objekte in einer Reihe anzuordnen, die von anderen Async-Funktionen verarbeitet werden können – zum Beispiel, um Workloads basierend auf ihrem Verhalten auf verschiedene Funktionen zu verteilen. Synchronization Primitives: Locks, Events, Conditions und Semaphores funktionieren in asyncio genauso wie ihre konventionellen Python-Gegenstücke. Sie sind darauf konzipiert, andere Arten von Aktivitäten zwischen Tasks zu koordinieren – beispielsweise, um auf eine Ressource zuzugreifen, die jeweils nur von einer Entität genutzt werden kann. Zu beachten ist, dass keine dieser Methoden Thread-Safe ist. Das ist kein Problem für Async-Tasks, die im selben Event Loop ausgeführt werden. Um Informationen mit Tasks in anderen Event Loops, Betriebssystem-Threads oder Prozessen zu teilen, sind Sie auf das Threading- Modul und seine Objekte angewiesen. Falls Sie Coroutines über Thread-Grenzen hinweg starten möchten, nutzen Sie die Funktion asyncio.run_coroutine_threadsafe() – und übergeben den zu verwendenden Event Loop als Parameter. Coroutines pausieren mit asyncio Über eine willkürliche Zeitspanne innerhalb einer Koroutine zu verharren, ist ein weiterer häufiger asyncio-Anwendungsfall, der eher selten diskutiert wird. Da Sie time.sleep() zu diesem Zweck nicht verwenden können (außer Sie wollen riskieren, das gesamte Programm zu blockieren), nutzen Sie stattdessen asyncio.sleep(). Das gewährleistet, dass andere Coroutines weiter ausgeführt werden können. Sollten Sie im Sinn haben, asyncio.sleep() in einem Loop zu verwenden:  Das ist theoretisch möglich, aber nicht empfehlenswert. Ein asyncio.Event-Objekt zu übergeben, ist der bessere Ansatz, da Sie einfach darauf warten können, dass dieses geändert wird. Async und File I/O in asyncio Standardmäßig blockiert lokaler File I/O den aktuellen Thread. Eine Möglichkeit, das Problem zu umgehen: Delegieren Sie den Vorgang mithilfe von asyncio.to_thread() an einen anderen Thread. So können andere Tasks weiterhin im Event Loop verarbeitet werden.   Eine andere Möglichkeit, File I/O asynchron zu verarbeiten, bietet die Drittanbieter-Bibliothek aiofiles. Sie enthält High-Level-Async-Konstrukte, um Dateien zu öffnen, zu lesen und zu schreiben. Low-Level-Async mit asyncio nutzen Falls Ihre Python-App Lower-Level-Komponenten von asyncio benötigt, stehen die Chancen gut, dass bereits eine entsprechende Async-Python-Bibliothek vorhanden ist, die genau das tut, was Sie brauchen – wie etwa asyncSSH für asynchrone SSH-Sitzungen. Die Awesome-Asnycio-Liste auf GitHub hält zahlreiche Inspirationen bereit. (fm) Sie wollen weitere interessante Beiträge zu diversen Themen aus der IT-Welt lesen? Unsere kostenlosen Newsletter liefern Ihnen alles, was IT-Profis wissen sollten – direkt in Ihre Inbox!

srcset=”https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?quality=50&strip=all 3458w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=300%2C168&quality=50&strip=all 300w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=768%2C432&quality=50&strip=all 768w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1024%2C576&quality=50&strip=all 1024w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1536%2C864&quality=50&strip=all 1536w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=2048%2C1152&quality=50&strip=all 2048w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=1240%2C697&quality=50&strip=all 1240w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=150%2C84&quality=50&strip=all 150w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=854%2C480&quality=50&strip=all 854w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=640%2C360&quality=50&strip=all 640w, https://b2b-contenthub.com/wp-content/uploads/2025/02/MagicMore_shutterstock_1786594046_16z9.jpg?resize=444%2C250&quality=50&strip=all 444w” width=”1024″ height=”576″ sizes=”(max-width: 1024px) 100vw, 1024px”>Die Python-Bibliothek asyncio unterstützt bei asynchronen Python-Tasks. Lesen Sie, wie’s geht.MagicMore | shutterstock.com Python-Programme zu schreiben, die nicht auf unabhängige Tasks warten müssen, wird mit der asynchronen Programmierfunktionalität – oder kürzer (und schöner) Async – möglich. Mit der asyncio-Bibliothek ist ein Toolset in Python integriert, um Disk- oder Network-I/O asynchron zu verarbeiten.    Zu diesem Zweck stellt asyncio zweierlei Arten von APIs zur Verfügung: High-Level-APIs sind besonders nützlich und auf die unterschiedlichsten Applikationen anwendbar. Low-Level-APIs sind besonders leistungsstark, aber auch komplex und kommen deswegen seltener zum Einsatz. In diesem Artikel werfen wir einen Blick auf die gängigsten High-Level-APIs von asyncio und erörtern anhand einiger Beispiele, wie Sie diese für asynchrone Python-Tasks einsetzen können. Abschließend gibt‘s auch noch einige Low(er)-Level-Async-Tipps. Coroutines und Tasks mit asyncio Naturgemäß dürfte asyncio am häufigsten zum Einsatz kommen, um die asynchronen Teile Ihres Python-Skripts auszuführen. Dazu sollten Sie wissen, wie Sie mit Coroutines und Tasks umgehen. Beides gehört zu den Async-Komponenten von Python. Diese können ausschließlich miteinander genutzt werden – nicht mit konventionellem, synchronen Python-Code. Um diesen „Gap“ zu überbrücken, kommt asyncio zum Einsatz. Vorausgesetzt, Sie nutzen die asyncio.run-Funktion: import asyncio async def main(): print (“Waiting 5 seconds. “) for _ in range(5): await asyncio.sleep(1) print (“.”) print (“Finished waiting.”) asyncio.run(main()) Sie bewirkt, dass main() – inklusive sämtlicher Coroutines, die es auslöst – ausgeführt wird. Allgemein gilt: Ein Python-Programm sollte nur ein einziges .run()-Statement aufweisen – ebenso wie es nur eine main()-Funktion enthalten sollte. Wird Async nicht mit der nötigen Sorgfalt verwendet, kann es den Control Flow eines Programms schwer lesbar machen. Mit einem Einstiegspunkt in den Async-Code Programms bleibt alles übersichtlich. Async-Funktionen können auch als Tasks, beziehungsweise Objekte, die Coroutines umschließen, geplant werden. async def my_task(): do_something() task = asyncio.create_task(my_task()) Dadurch wird my_task() im Event Loop ausgeführt, die Ergebnisse in task gespeichert. Tasks sind vor allem dann nützlich, wenn Sie etwas einrichten möchten, das zunächst im Hintergrund laufen und zu einem späteren Zeitpunkt Ergebnisse liefern soll. Ein Task könnte beispielsweise in einer Liste gespeichert werden, wo sich die Ergebnisse anschließend überprüfen lassen – entweder zu einem geplanten Zeitpunkt oder on demand.   Wenn Sie nur einen Task haben, von dem Sie Ergebnisse erwarten, können Sie mit asyncio.wait_for(task) darauf warten, dass dieser beendet wird und mit task.result() das Ergebnis abrufen. Wenn Sie damit planen, mehrere Tasks auszuführen und warten möchten, bis alle abgeschlossen sind, nutzen Sie asyncio.wait([task1, task2]), um die Ergebnisse zu sammeln. Sie können auch einen Timeout für die Operationen setzen, wenn Sie einen bestimmten Zeitrahmen nicht sprengen sollen. Event Loop mit asyncio managen Beim Event Loop handelt es sich um ein Objekt, das Async-Funktionen und -Callbacks ausführt. Es wird automatisch erstellt, sobald Sie die asyncio.run()-Funktion nutzen. Um die Übersicht zu wahren, empfiehlt es sich, nur einen asynchronen Event Loop pro Programm zu verwenden. Falls Sie fortgeschrittenere Software schreiben möchten, etwa die für einen Server, brauchen Sie Lower-Level-Zugang zum Event Loop. Dazu arbeiten Sie am besten direkt mit seinen internen Komponenten. Für einfache Aufgaben ist das nicht erforderlich. Daten über asyncio mit Streams lesen und schreiben Langlaufende Netzwerk-Prozesse sind für Async ein ideales Szenario. Hierbei könnte die Applikation blockiert werden, weil sie darauf wartet, dass eine andere Ressource Ergebnisse zurückgibt. Um dieses Problem zu beheben, bietet asyncio sogenannte Streams. Dabei handelt es sich um High-Level-Mechanismen, die für Network-I/O-Aufgaben zum Einsatz kommen. In diesem Zuge fungieren sie auch als Server für Netzwerk-Requests.   Für Netzwerk-Read- und -Write-Vorgänge auf hoher Ebene nutzt asyncio zwei Klassen: StreamReader und StreamWriter. Wenn Sie einen Netzwerk-Read-Vorgang starten wollen, nutzen Sie asyncio.open_connection(), um die Verbindung herzustellen. Diese Funktion gibt ein Tupel von StreamReader– und StreamWriter-Objekten zurück. Für die Kommunikation kommen jeweils die Methoden .read() und .write() zum Einsatz. Um Verbindungen von Remote-Hosts zu empfangen, nutzen Sie asyncio.start_server(). Die Funktion nutzt client_connected_cb als Callback-Funktion, die immer dann aufgerufen wird, wenn sie eine Anfrage erhält. Die Callback-Funktion nimmt Instanzen von StreamReader und StreamWriter als Argumente, sodass Sie die Read/Write-Logik für den Server verarbeiten können. (hier ein simples Beispiel für einen HTTP-Server, der die asyncio-gesteuerte aiohttp-Bibliothek verwendet.) Tasks synchronisieren mit asyncio Asynchrone Tasks werden in der Regel isoliert ausgeführt, sollen manchmal aber miteinander kommunizieren. Um zwischen Tasks zu synchronisieren, bietet asyncio mehrere Mechanismen: Queues: Warteschlangen ermöglichen es asynchronen Funktionen, Python-Objekte in einer Reihe anzuordnen, die von anderen Async-Funktionen verarbeitet werden können – zum Beispiel, um Workloads basierend auf ihrem Verhalten auf verschiedene Funktionen zu verteilen. Synchronization Primitives: Locks, Events, Conditions und Semaphores funktionieren in asyncio genauso wie ihre konventionellen Python-Gegenstücke. Sie sind darauf konzipiert, andere Arten von Aktivitäten zwischen Tasks zu koordinieren – beispielsweise, um auf eine Ressource zuzugreifen, die jeweils nur von einer Entität genutzt werden kann. Zu beachten ist, dass keine dieser Methoden Thread-Safe ist. Das ist kein Problem für Async-Tasks, die im selben Event Loop ausgeführt werden. Um Informationen mit Tasks in anderen Event Loops, Betriebssystem-Threads oder Prozessen zu teilen, sind Sie auf das Threading- Modul und seine Objekte angewiesen. Falls Sie Coroutines über Thread-Grenzen hinweg starten möchten, nutzen Sie die Funktion asyncio.run_coroutine_threadsafe() – und übergeben den zu verwendenden Event Loop als Parameter. Coroutines pausieren mit asyncio Über eine willkürliche Zeitspanne innerhalb einer Koroutine zu verharren, ist ein weiterer häufiger asyncio-Anwendungsfall, der eher selten diskutiert wird. Da Sie time.sleep() zu diesem Zweck nicht verwenden können (außer Sie wollen riskieren, das gesamte Programm zu blockieren), nutzen Sie stattdessen asyncio.sleep(). Das gewährleistet, dass andere Coroutines weiter ausgeführt werden können. Sollten Sie im Sinn haben, asyncio.sleep() in einem Loop zu verwenden:  Das ist theoretisch möglich, aber nicht empfehlenswert. Ein asyncio.Event-Objekt zu übergeben, ist der bessere Ansatz, da Sie einfach darauf warten können, dass dieses geändert wird. Async und File I/O in asyncio Standardmäßig blockiert lokaler File I/O den aktuellen Thread. Eine Möglichkeit, das Problem zu umgehen: Delegieren Sie den Vorgang mithilfe von asyncio.to_thread() an einen anderen Thread. So können andere Tasks weiterhin im Event Loop verarbeitet werden.   Eine andere Möglichkeit, File I/O asynchron zu verarbeiten, bietet die Drittanbieter-Bibliothek aiofiles. Sie enthält High-Level-Async-Konstrukte, um Dateien zu öffnen, zu lesen und zu schreiben. Low-Level-Async mit asyncio nutzen Falls Ihre Python-App Lower-Level-Komponenten von asyncio benötigt, stehen die Chancen gut, dass bereits eine entsprechende Async-Python-Bibliothek vorhanden ist, die genau das tut, was Sie brauchen – wie etwa asyncSSH für asynchrone SSH-Sitzungen. Die Awesome-Asnycio-Liste auf GitHub hält zahlreiche Inspirationen bereit. (fm) Sie wollen weitere interessante Beiträge zu diversen Themen aus der IT-Welt lesen? Unsere kostenlosen Newsletter liefern Ihnen alles, was IT-Profis wissen sollten – direkt in Ihre Inbox! 

Nach oben scrollen
×