Bei der sequentiellen Programmierung stoße ich ständig auf den offensichtlichen Wunsch, das Programm nicht zu einem Zeitpunkt anzuhalten, an dem das Ziel einzelner Aufgaben (Prozesse) regelmäßige Aktionen sind - beispielsweise das Abrufen von Sensorwerten oder das Übertragen von Daten nach einem Zeitplan an einen Server oder das Eingeben / Ausgeben einer großen Datenmenge. Am einfachsten ist es natürlich, auf den Abschluss des periodischen Ereignisses zu warten und dann langsam andere Aufgaben auszuführen.
while True: do_ext_proc_before() do_internal_proc() sleep(5) do_ext_proc_after()
Sie können 'sleep ()' abbrechen und die Überprüfung auf einige Bedingungen in der Schleife aktivieren, sodass Sie die Hauptschleife nicht mindestens bis zum Auftreten eines periodischen Ereignisses verzögern können:
start = time() set_timer(start,wait=5)
Bei der asynchronen Programmierung wird jede Aufgabe zu einem unabhängigen Prozess und wird je nach spezifischer Implementierung parallel oder pseudo-parallel ausgeführt, wobei ein internes Verständnis der natürlichen oder künstlich festgelegten Wartebedingungen oder die Verwendung einer begrenzten Ressource, beispielsweise einer Festplatte oder eines Kommunikationskanals, verwendet wird.
setTask(do_ext_proc_before()) setTask(do_internal_proc(),timer=5,timeout=7,alarm_handler=alarm) setTask(do_ext_proc_after()) runTasks()
Jetzt tritt ein Problem auf, das bei der sequentiellen Programmierung nicht vorhanden ist - was ist zu tun, wenn einige Prozesse mit ihren asynchronen synchronisiert werden müssen?
tun? Wenn Sie beispielsweise Daten von Sensoren empfangen haben, starten Sie den Prozess des Sendens von Daten an einen Server oder reagieren Sie auf einen Notfall. Darüber hinaus wird bei der asynchronen Programmierung die Organisation der asynchronen Eingabe / Ausgabe im Sprachstandard organisch gelöst, und andere Situationen werden in Bibliotheken gelöst.
Ich habe diese Frage mit der veröffentlichten erweiterten asyncio Micropython-Bibliothek untersucht
Peter Hinch ( https://github.com/peterhinch/micropython-async/blob/master/TUTORIAL.md )
Die einfachste Lösung besteht darin, das Ereignis interessierten Prozessen zu signalisieren. Verwenden Sie dazu die Event () -Klasse, die mehrere Module enthält
Event.Set( timeout = None, data = None ) - (Event = True), , , Event.IsSet() - , , True, False Event.Wait() - , - Done,Timeout,Cancel Event.Data() - , Event.Clear() - (Event = False).
Der Abschluss wird in der Regel von dem Prozess aufgezeichnet, der auf das Eintreten des Ereignisses wartet, z. B. der Anzeige auf dem Bildschirm oder das Speichern von Daten auf der Festplatte oder das Zeitlimit. Dann müssen die Daten nicht aktualisiert oder gespeichert werden, da sie aus irgendeinem Grund nicht aktualisiert werden Aufgrund seiner Unterbrechung beim Auftreten eines anderen wichtigen Ereignisses, z. B. beim Übergang in den Ruhemodus oder beim Neustart, müssen möglicherweise alle anstehenden Prozesse durch Zurücksetzen der entsprechenden Ereignisse freigegeben werden.
Es sollte beachtet werden, dass es ratsam ist, Event.Clear () mit nur einem Prozess zu erstellen, wenn dies nicht dem angegebenen Algorithmus widerspricht. Wenn andernfalls mehrere Prozesse auf das Ereignis Event.Set () warten, wird davon ausgegangen, dass Event.Clear () von einem der interessierten Prozesse ausgeführt wird, wobei nur sichergestellt wird, dass alle interessierten Prozesse auf das Ereignis reagiert haben. Dies verkompliziert die Entscheidungslogik bei Verwendung der Ereignisklasse, wenn mehrere Prozesse auf ein Ereignis warten. Diese Situation wird gelöst, indem eine bestimmte Anzahl von Clear () für das aufgetretene Ereignis festgelegt wird.
Barrier.Set( quantity = 1, timeout = None, data = None ) - quantity = 1 Event.Set() Barrier.IsSet() - , , True, False Barrier.Wait() - , - Done,Timeout,Cancel Barrier.Data() - , Barrier.qty - Barrier.Clear() - (Event = False), Barrier.quantity , ,
Gleichzeitig wird keine Buchhaltung geführt - welcher spezifische Prozess hat bereits reagiert und welcher noch nicht, was zu dem Problem der erneuten Reaktion auf das Ereignis führen kann, wenn dies für einen bestimmten Algorithmus wesentlich ist. Wenn Sie anstelle von Barrier.quantity eine Liste mit Namen interessierter Prozesse übergeben, kann dieser Konflikt vermieden werden. Außerdem können Sie im Falle eines Timeouts oder einer Unterbrechung des Ereignisses feststellen, welche spezifischen ausstehenden Prozesse noch nicht funktioniert haben. All dies gilt für eine Situation, in der ein oder mehrere Prozesse auf das Eintreten eines bestimmten Ereignisses warten, oder für eine Eins-zu-Viele-Situation. Dies tritt auf, wenn der Prozess oder die Prozesse do_ext_proc_after () während der sequentiellen Programmierung erst nach Abschluss von do_internal_proc () ausgeführt werden. Zum besseren Verständnis werden wir die vorhandene Event-Klasse und Barrier-Klasse in die neue EEvent-Klasse erweitern und sie oder die von ihr generierten Objekte global machen. Hier ist "Ersteller" der Name oder die Liste der Namen von Prozessen, die das Ereignis auslösen oder die Ressource entsperren. "Ordner" ist der Name oder die Liste der Namen von Prozessen, die auf das Ereignis warten oder die Ressource entsperren
EEvent.Set (creators, folowers, timeout = None, data = None ) - True, EEvent.IsSet( procName ) - procName - ID EEvent.Wait( procName ) EEvent.Clear( procName ) EEvent.Folowers() - , . Barrier.qty = len(EEvent.List()) EEvent.Creators() - ,
Mit den Modulen der EEvent-Klasse können wir die Lösung des zuvor diskutierten Problems beschreiben.
def do_internal_proc(): ... EEvent.Set ('p_Creator',('p_Folwer1','p_Folwer2'))
Stellen Sie sich die umgekehrte Situation vor - wenn ein Prozess auf den Abschluss mehrerer Ereignisse wartet oder eine Situation mit vielen zu einem. Mit anderen Worten, wenn die Ausführung von do_internal_proc () erst nach der Ausführung von do_ext_proc_before () erfolgen kann. Im Extremfall, wenn ein Prozess auf den Abschluss / das Auftreten eines Ereignisses wartet, kann die Aufgabe mithilfe der Ereignisklasse gelöst werden. Wenn der Abschluss mehrerer Ereignisse erwartet wird, z. B. erst nachdem die empfangenen Daten angezeigt und an den Server gesendet und auf der Festplatte gespeichert wurden, muss jeder ausgeführte Prozess seine Teilnahme am erwarteten Ereignis herstellen und warten, bis alle Prozesse abgeschlossen sind.
def do_ext_proc_before1() ... EEvent.Set('p_Creator1','p_Folwer') ... def do_ext_proc_before2() ... EEvent.Set('p_Creator2','p_Folwer') ... def do_internal_proc(): ... EEvent.Wait(('p_Creator1','p_Creator2')) ... EEvent.Clear('p_Folwer')
Ein weiterer wichtiger Aspekt der asynchronen Programmierung ist die gemeinsame Nutzung einer begrenzten Ressource. Beispielsweise sollte die Datenaktualisierung nur von einem Prozess durchgeführt werden. Der Rest der Prozesse, die eine ähnliche Aktion beanspruchen, muss sich in der Warteschlange befinden oder warten, bis die Daten aktualisiert werden. Gleichzeitig ist es möglich, dass das Lesen von Daten zur Anzeige oder Weiterleitung nicht kritisch ist. Daher ist es notwendig, die Liste der konkurrierenden Prozesse zu kennen, wenn relevante Ereignisse organisiert werden.
Im asynchronen Programmierstandard wird diese Aufgabe durch Lock-Class-Module gelöst. Im allgemeinen Fall kann das Problem auch ähnlich wie in der Eins-zu-Viele-Situation gelöst werden.
def do_internal_proc():
Zusätzlich zu den in Betracht gezogenen Optionen gibt es Lösungen, die den Durchsatz begrenzen, Warteschlangen organisieren und die Planung von Prozessen steuern. In meiner Tätigkeit bestand jedoch noch kein Bedarf dafür und daher ein Bedürfnis nach ausreichendem Verständnis für mich selbst, obwohl ich nicht ausschließe, dass es elegantere oder elegantere gibt wirtschaftliche Entscheidungen.
Abschließend möchte ich sagen, dass sequentielle und asynchrone Ansätze das gleiche Recht haben, zu existieren und die gegebenen Algorithmen erfolgreich zu implementieren. Daher wird die Anwendung dieses oder jenes Ansatzes durch die Prioritäten des Erstellers bestimmt - was für ihn bei der Implementierung der gegebenen Algorithmen wichtiger ist - Transparenz und Lesbarkeit, Geschwindigkeit oder Volumen des resultierenden Codes.