MicroPython: asyncio / async

Das Asyncio-Konzept ist kooperatives Multitasking. Diese Technik ist in eingebetteten Systemen und Mikrocontrollern weit verbreitet. Es ermöglicht Multitasking auf einem vergleichsweise niedrigem Niveau. Während der Anwendungsentwickler auf einem System mit einer Universal-CPU das Multitasking dem Betriebssystem überlassen kann, muss er in Mikrocontrollern, wie zum Beispiel dem Raspberry Pi Pico, gewisse konzeptionelle Vorbereitungen treffen, damit sein Programmcode quasi parallel arbeiten kann. Und tatsächlich wird hier nichts parallel, sondern immer noch streng nacheinander ausgeführt. Allerdings kann der Programmierer innerhalb des Programmcodes Warte-Kommandos setzen, in deren Zeit ein anderer Programmteil ausgeführt wird. Bei hoher Rechenleistung fühlt sich das für den Anwender so an, als ob er ein parallel verarbeitendes System vor sich hat. Dabei ist das nur Quasiparallelität. „Quasi“ bedeutet „sozusagen“, „gewissermaßen“ oder „so gut wie“ (Quelle: Duden).

Beim kooperativen Multitasking werden zwar auch, wie beim preemptiven Multitasking, durch den Scheduler, ein Teil des Betriebssystems, Prioritäten an die einzelnen Tasks vergeben. Allerdings kann es hier vorkommen, dass der Task (die Aufgabe) mit der höchsten Priorität die Rechenzeit- und die Leistung für sich alleine beansprucht. Dadurch werden unter Umständen die anderen Tasks geblockt und müssen „warten“.

Zum besseren Verständnis muss man wissen, dass die Funktionen asynchron ausgeführt werden und dabei eine Quasiparallelität entsteht. Jede Funktion wird trotzdem nacheinander ausgeführt. Es ist wichtig, dass der Programmierer vor dem Ende einer Funktion eine Pause mit „await“ vorsieht. Nur so haben die anderen Funktionen die Möglichkeit auch Rechenzeit zu bekommen.

MicroPython-Modul „asyncio“

Die Python-Bibliothek „asyncio“ gibt es seit der Python-Version 3.7. Das Python-Modul „asyncio“ ermöglicht es dem Programmierer mit Hilfe von kooperativem Multitasking eine Quasiparallelität zu erreichen und die Rechenleistung des Mikrocontrollers auszureizen.
Das MicroPython-Modul „asyncio“ ist sehr umfangreich und sehr komplex. Desweiteren muss man berücksichtigen, dass wenn man „asyncio“ nutzen möchte, dass der gesamte Programmcode den Regeln dieses Konzepts folgen muss. Wenn man einen sequentiellen Programmcode nur in Teilen asynchron arbeiten lässt, dann werden die asynchronen Teile nicht besonders gut funktionieren bzw. nicht genug Zeit zur Verarbeitung bekommt.
Echte Parallelität ist mit „asyncio“ nicht möglich, weil der Programmcode in Python bzw. MicroPython grundsätzlich in einem Thread abläuft. Allerdings kann man mit „asyncio“ Performancesteigerungen auch ohne Multithreading erreichen. Allerdings muss der Programmierer seinen Code entsprechend optimieren. Gemeint ist, dass die Funktionen im Programmcode zeitlich verschachtelt ausgeführt werden können.

Beispiel: Programmcode ohne „asyncio“

Was macht der folgende Programmcode? Im Programmcode gibt es zwei Funktionen. Eine Funktion gibt die Zahlen „1“ und „2“ auf der Kommandozeile aus. Dazwischen macht der Programmablauf eine Sekunde Pause. In der zweiten Funktion (Hauptprogramm) wird die erste Funktion durch die Schleife insgesamt 3 Mal ausgeführt.
Das Hauptprogramm ruft die erste Funktion auf. Davor und dahinter wird die Zeit gestoppt und ermittelt, wie lange der Programmablauf gedauert hat.

# Bibliotheken laden
import time

# Funktion
def count():
    print('1')
    time.sleep(1)
    print('2')

# Hauptprogramm
def main():
    for _ in range(3): count()

# Zeitmessung starten
start = time.ticks_ms()

# Hauptprogramm ausführen
main()

# Zeitmessung stoppen und Ergebnis ausgeben
stop = time.ticks_ms()
print('Dauer der Ausführung:', time.ticks_diff(stop, start) / 1000, 'Sekunden')

Beispiel: Programmcode mit „asyncio“

Was macht der folgende Programmcode? Im Programmcode gibt es zwei Funktionen. Eine Funktion gibt die Zahlen „1“ und „2“ auf der Kommandozeile aus. Dazwischen macht der Programmablauf eine Sekunde Pause. In der zweiten Funktion (Hauptprogramm) wird die erste Funktion insgesamt 3 Mal asynchron ausgeführt.
Das eigentliche Hauptprogramm darunter ruft die zweite Funktion auf. Davor und dahinter wird die Zeit gestoppt und ermittelt, wie lange der Programmablauf gedauert hat.

# Bibliotheken laden
import asyncio

# Funktion
async def count():
    print('1')
    await asyncio.sleep(1)
    print('2')

# Hauptprogramm
async def main():
    await asyncio.gather(count(), count(), count())

# Zeitmessung starten
import time
start = time.ticks_ms()

# Hauptprogramm ausführen
asyncio.run(main())

# Zeitmessung stoppen und Ergebnis ausgeben
stop = time.ticks_ms()
print('Dauer der Ausführung:', time.ticks_diff(stop, start) / 1000, 'Sekunden')

Was ist der Unterschied zwischen dem Programmcode mit und ohne „asyncio“?

Hinweis: Grundsätzlich ist es immer schwierig Äpfel mit Birnen zu vergleichen. Das ist hier auch so. Erst einmal hat man durch die Verwendung von „asyncio“ keinen Vorteil. Im Gegenteil. Durch „asyncio“ wird der Programmcode komplizierter und unübersichtlicher. Was genau der Unterschied ist und ob man daraus einen Vorteil ziehen kann, musst Du im konkreten Anwendungsfall herausarbeiten.

Grundsätzlich sind beide Programmcodes funktional identisch. Es geht darum, die Zahlen „1“ und „2“ mit einem Zeitversatz von einer Sekunde insgesamt 3 Mal auf der Kommandozeile auszugeben.
Im Programmcode OHNE „asyncio“ erfolgt die Ausführung streng nacheinander. Entsprechend dauert die Ausführung des Programmcodes etwas über 3 Sekunden, was der Summe der Wartezeit zwischen en einzelnen Datenausgaben (print) entspricht.
Im Programmcode MIT „asyncio“ erfolgt die Ausführung verschachtelt. Das heißt, eine Pause verstreicht hier nicht ungenutzt, sondern wird für die Ausführung einer anderen Funktion verwendet, die darauf wartet ausgeführt zu werden. Zwischen der Ausgabe von „1“ und „2“ findet immer noch eine Pause von einer Sekunde statt. Allerdings wird diese nicht mehr im Programmablauf aufaddiert. Dadurch dauert der Programmablauf nur etwas über eine Sekunde.

Der Vorteil von „asyncio“ ist, dass Wartezeiten im Programmcode, die durch „time.sleep“ entstehen, von anderen Teilen des Programmcodes (Funktionen) genutzt werden können, um die Rechenleistung besser auszulasten.

Der Nachteil von „asyncio“ ist, dass die Nutzung nur Sinn macht, wenn innerhalb des Programmcodes Wartezeiten durch „time.sleep“ entstehen. Wenn kein „time.sleep“ verwendet wird, dann macht „uasyncio“ keinen Sinn, es sei denn man findet einen Weg, künstliche Wartezeiten einzubauen.

Brauche ich kooperatives Multitasking?

Wenn man am Anfang eines Programmcodes steht, dann darf auch die Frage gestellt werden, ob kooperatives Multitasking sinnvoll ist. Nachträglich einen Programmcode auf „asyncio“ umzustellen, bedeutet im Regelfall fast alles neu zu schreiben.
Sollte man also grundsätzlich seinen Programmcode für kooperatives Multitasking planen?

Schwer zu sagen. Eine Lösung wie „asyncio“ macht nur dann Sinn, wenn man die in einem Programmcode eingebauten Wartenzeiten anderweitig nutzen muss oder kann, um nebenläufigen Funktionen unabhängig von der Ausführung in einer Schleife durchzuführen.
Allerdings gibt es je nach Anwendungsfall auch andere Lösungen. Beispielsweise Timer- und Interrupt-Steuerungen.

Anwendungen mit „uasyncio“

Weitere verwandte Themen:

Frag Elektronik-Kompendium.de

Hardware-nahes Programmieren mit dem Raspberry Pi Pico und MicroPython

Elektronik-Set Pico Edition

Das Elektronik-Set Pico Edition ist ein Bauteile-Sortiment mit Anleitung zum Experimentieren und Programmieren mit MicroPython.

  • LED: Einschalten, ausschalten, blinken und Helligkeit steuern
  • Taster: Entprellen und Zustände anzeigen
  • LED mit Taster einschalten und ausschalten
  • Ampel- und Lauflicht-Steuerung
  • Elektronischer Würfel
  • Eigene Steuerungen programmieren

Elektronik-Set jetzt bestellen Online-Workshop buchen

Online-Workshop: Programmieren mit dem Raspberry Pi Pico

Programmieren mit dem Raspberry Pi Pico

Gemeinsam mit anderen und unter Anleitung experimentieren? Wir bieten unterschiedliche Online-Workshops zum Raspberry Pi Pico und MicroPython an. Einführung in die Programmierung, Sensoren programmieren und kalibrieren, sowie Internet of Things und Smart Home über WLAN und MQTT.

Online-Workshop buchen

Besuchen Sie unser fast monatlich stattfindendes Online-Meeting PicoTalk und lernen Sie uns kennen. Die Teilnahme ist kostenfrei.

Termine und Newsletter-Anmeldung

 

Elektronik-Sets für das Hardware-nahe Programmieren