NEWS
synchronize/locking scripts
-
Ich stehe immer wieder vor dem Problem dass eine gute Methode fehlt Zugriffe zu synchronisieren.
Problem: D.h. wenn z.B. mehrere Skripte einen State lesen ->Wert (z.B. Counter) erhöhen, und wieder schreiben. Das funktioniert nur ordentlich, wenn alle (lesen->ändern->schreiben) Vorgänge "nacheinander" bzw. geordnet ablaufen.
Ich habe mir jetzt mit messageTo onMessage beholfen - ein Script verwaltet eine Art Queue und führt einen Job nach dem anderen aus.
await synchronized("my_ID",async function(){ var state=getState("my_ID"); await setStateAsync("my_ID",state.val++); });
Dieser Aufruf stellt dann sicher, dass alle so aufgerufenen Code-Blöcke nacheinander ausgeführt werden - auch über verschiedene Scripts hinweg.
Allerdings ist sendMessage nicht sehr schnell - da gibt es doch sicher bessere Wege, oder?
-
und was wäre der konkrete anwendungsfall?
wenn du so schnell hintereinander bspw einen counter bedienen willst, könnte sein, das der ansatz counter schon falsch ist.datenpunkte sind langsame ressourcen. da läuft schon einiges an logik dahinter, bis zur Persistenz ebene, also speichern in jsonl, redis, mysql, history etc.
wenn man unbedingt zählen muss, dann reicht es evtl das im speicher über eine variable zu machen und nur alle paar sekunden den zähler in einem datenpunkt aktualisieren.
-
Ich denke, ich weiß was du meinst.
ioBroker arbeitet üblicherweise mit einer Eventsteuerung.
Eine Änderung eines Datenpunktes löst unmittelbar eine Aktion aus.
Ist bei Systemen dieser Art quasi Standard.
Sind nun an einem Prozess mehrere, unter Umständen abhängige Datenpunkte beteiligt, führt das zu einer Häufung von Events mit dann teils undefinierter Bearbeitungsreihenfolge. Sowas kann sich soweit Aufschaukeln, dass ein System nicht mehr nutzbar ist.Ich komme aus der industriellen Steuerungstechnik. Dort arbeiten wir mit PLC-Steuerungen.
Zum Beispiel Siemens S7 oder Codesys basierte Systeme. Eine PLC arbeitet mit einer kontinuierlichen zyklischen Programmausführung.- Alle Zustände erfassen
- Logische Bearbeitung
- Geänderte Zustände ausgeben
So ein Programmzyklus dauert ein paar Millisekunden.
Das Erfassen der Zustände am Start und das Ausgeben der Änderungen am Ende sorgt dafür, dass du während der logischen Bearbeitung konsistente Daten hast.
Die Bearbeitung läuft einfach in der programmierten Reihenfolge durch.
Synchronistation, Sperren oder Ähnliches entfällt dadurch.Ich habe mein Energiemanagement für PV, Speicher, Wallbox und Heizstab auf diese Weise umgesetzt.
Dazu rufe ich einfach ein Script jede Sekunde auf. Also nur noch ein zyklisches Event anstelle ca. 10-15 Triggern auf Datenpunkte.Mir ist klar, dass diese Art der Programmierung nicht typisch für ioBroker ist.
Aber das ist ja das Schöne an ioBroker, dass man da eben auch solche Lösungen umsetzen kann. -
@blockmove sagte in synchronize/locking scripts:
Dazu rufe ich einfach ein Script jede Sekunde auf.
ich frage mich immer wieder WARUM.. was braucht man so dringend an Daten dass diese pro sekunde abgerufen oder geschrieben werden MÜSSEN
und nur weil es geht.. ergibt es keinen Sinn.
der sinn (oder unsinn) liegt in der parallelel Verabreitung.. das was du machst ist : ich zwinge die Scripte zur sequenzoellen Verarbeitung..
warum.. will ich das.. eher nicht.. da sich ein geänderter DP Auswirkung auf mehrere Scripte hat die paralell abgearbeitet werden können..ich gebe dir recht dass manche Sachen hintereinander laufen sollen.. aber dann in einem Script ..und nicht verteilt über mehrere Scriptedie du dann beschneidest in der paralelität
-
Nun ja, der Grundsatz einer Serialisierung ist aber auch bei ganz seltenen Events nicht unnötig.
Auch wenn ich einen Zähle nur 1 mal am Tag von 3 Scripts erhöhen möchte, muss ich sicherstellen, dass diese das nicht gelichzeitig tun. Weil lesen - verändern - schreiben ist nunmal nicht atomar. Natürlich ist es bei seltenen, asynchronen Vorgängen unwahscheinlicher dass ein Konflikt auftritt - ausgeschlossen ist es aber nicht.
P.S: Lösung hab ich nicht parat - leider
-
@arteck said in synchronize/locking scripts:
@blockmove sagte in synchronize/locking scripts:
Dazu rufe ich einfach ein Script jede Sekunde auf.
ich frage mich immer wieder WARUM.. was braucht man so dringend an Daten dass diese pro sekunde abgerufen oder geschrieben werden MÜSSEN
und nur weil es geht.. ergibt es keinen Sinn.
der sinn (oder unsinn) liegt in der parallelel Verabreitung.. das was du machst ist : ich zwinge die Scripte zur sequenzoellen Verarbeitung..
warum.. will ich das.. eher nicht.. da sich ein geänderter DP Auswirkung auf mehrere Scripte hat die paralell abgearbeitet werden können..ich gebe dir recht dass manche Sachen hintereinander laufen sollen.. aber dann in einem Script ..und nicht verteilt über mehrere Scriptedie du dann beschneidest in der paralelität
Event basierte oder zyklische Verarbeitung sind beides Standard in der Steuerungs- und Prozesstechnik. Das seit etlichen Jahrzehnten. Moderne Steuerungsysteme haben meist beide Möglichkeiten. Je nach Anwendungsfall hat das eine System oder das andere System Vorzüge / Nachteile. Die allermeisten Aufgaben lassen sich mit beiden Systemen lösen.
Arbeite ich nur mit Events und hab dazu noch Parallität (Mutlitask / Multithread) habe ich das Problem, dass ich abhängig von den Bedingungen des Prozesses für konsistente Daten / Zustände sorgen muss. Hierzu brauchst du Mechanismen zur Prozess-Synchronisation (Semaphoren, Queues, Scheduler, ...). Je mehr I/O umso komplexer wird das Ganze. Ich denke, dass @coalado in so einer Situation ist und deshalb den Thread hier eröffnet hat.
Diese Komplexität umgehe ich mit einer zyklischen Programmbearbeitung und der Bildung eines sogenannten Prozessabbildes. Beim Scriptstart wird der Zustand aller benötigten Signale in Variablen eingelesen. Dann wird die Logik mit diesen Zustandsvariablen abgearbeitet und anschließend werden die Änderungen ausgegeben. Also Read Compute Write. Das ist die Arbeitsweise einer PLC. RCW ist auch die Arbeitsweise bei der Threadsafe-Programmierung. Vielleicht macht der Begriff Threadsafe es einigen leichter verständlich. -
@coalado sagte: mehrere Skripte einen State lesen ->Wert (z.B. Counter) erhöhen, und wieder schreiben.
Das Schreiben eines Datenpunktes macht man nur in einem Skript.
-
@blockmove sagte in synchronize/locking scripts:
Diese Komplexität umgehe ich mit einer zyklischen Programmbearbeitung und der Bildung eines sogenannten Prozessabbildes
ja gebe ich dir recht.. bei CNC oder wo es unbedingt nötig ist einer nach-und-nach Verarbeitung..
bei events sind wir ein einer anderen Welt.. wenn einer feuert muss das andere Event nicht drauf warten bis event1 (laufzeit sagen wir mal 10 min,warum auch immer) fertig ist
du kannst auch mit sperren arbeiten.. wie es in der DB ist. der Datensatz wird gesperrt wenn einanderer was ren schreibt.. aber wie gesagt..
ich finde man sollte eine Eventbasierte anwendung nicht beschnieden und diese in eine sequenzielle reinpressen.. -
@arteck said in synchronize/locking scripts:
@blockmove sagte in synchronize/locking scripts:
Diese Komplexität umgehe ich mit einer zyklischen Programmbearbeitung und der Bildung eines sogenannten Prozessabbildes
ja gebe ich dir recht.. bei CNC oder wo es unbedingt nötig ist einer nach-und-nach Verarbeitung..
bei events sind wir ein einer anderen Welt.. wenn einer feuert muss das andere Event nicht drauf warten bis event1 (laufzeit sagen wir mal 10 min,warum auch immer) fertig ist
du kannst auch mit sperren arbeiten.. wie es in der DB ist. der Datensatz wird gesperrt wenn einanderer was ren schreibt.. aber wie gesagt..
ich finde man sollte eine Eventbasierte anwendung nicht beschnieden und diese in eine sequenzielle reinpressen..Ich will überhaupt nicht an der eventbasierten Verarbeitung rütteln.
Man kanns ja auch so sehen, dass ich nur ein weiteres Timerevent und ein paar Variablen für meine zykische Bearbeitung hinzugefügt habeDas Schöne an ioBroker ist ja eben, dass mir das System die Flexibilität lässt.
Wenn du ne CNC ansprichst, dann arbeiten die modernen Steuerungen da auch nicht anders.
Die Steuerungen haben CNC, PLC und Visu integriert. CNC eben für Drehen, Fräsen oder sonstwas, PCL für Schmierung, Kühlung, Werkzeugwechsel und Visu eben für Bedienen und Diagnose.
Alte Handwerkerregel: Für jede Arbeit das richtige Werkzeug nehmen. -
@blockmove
Sorry für die später Antwort.Zum "Warum":
Ich habe das Beispiel mit dem Counter gewählt, weil es einfach zu verstehen ist. Praktisch mache ich das nicht. Ich mache das auch in der Regel nicht mehrfach pro Sekunde - aber es geht halt um die theoretische Möglichkeit von Fehlern - auch wenn sowas bei normaler Nutzung nur selten passiert - ist es trotzdem ein Problem.Praktisch geht es eher um Dinge, dass ich Scripte habe, die z.B. Enums anlegen, und diesen Enums Datenpunkte zuordne. An anderer Stelle lese ich eben diese Enums und Datenpunkte aus, um z.B. Geräte für den IOT Adapter zu erstellen (Ich erstelle die selbst, und nutze nicht die "Logik" des IOT Adapters). Dazu muss ich in verschiedenen Scripts Objects lesen/bearbeiten. Das muss synchronisiert sein, weil es sonst zu besagten Problemen kommen kann.
Mir ist völlig klar, dass das weit über das hinausgeht was die meisten mit IOBroker machen, und vermutlich sollte ich das auch nicht via Script-Adapter, sondern über einen eigenen Adapter machen.
Aber gibt es für Adapter passende Konzepte? Oder verlässt man sich da drauf, dass ein Adapter nur die eigenen Objekte/States modifiziert? -
Ich denk du hast durch den Thread hier schon einige Stichworte erhalten. Wichtig ist halt primär, dass man sich über das Systemverhalten bewusst ist.
Einen eigenen Adapter brauchst du nicht. Einfach nur beim Programmieren darauf achten.