Autor Thema: [gelöst] Perl Alternative zu Fhem-Sleep/InternalTimer welche anonyme Sub erlaubt  (Gelesen 845 mal)

Offline Thyraz

  • Sr. Member
  • ****
  • Beiträge: 728
Hallo zusammen,

nachdem mir das Thema während der letzten Monate immer wieder aufgestoßen ist,
schreib ich doch mal einen Erweiterungswunsch dazu:

Mich stört, dass ich in Perl Funktionen oder Modulen zum Verzögern von Befehlen immer auf InternalTimer zurückgreifen muss.
Genauer gesagt, dass man bei InternalTimer einen Funktionsname statt einen Zeiger oder alternativ eine anonyme Sub übergibt.

Dadurch müssen die verzögerten Befehle in eine extra Funktion ausgelagert werden, was bei Ein- bis Zweizeilern den Code unnötig fragmentiert.
Z.B. Aufruf des ganzen in einem Notify, Verzögerter Code in einer Sub in einer MyUtils.
Wenn man asynchrone Verarbeitung aus anderen Sprachen mit verzögerten Inline-Blöcken/-Closures kennt, weckt das eben Begehren. ;)
In Notifies kann man ggf. noch auf sowas ausweichen:
fhem("sleep 5;{Log 1, 'Test'}");

Spätestens in Modulen fühlt sich das aber "dirty" an.
Auch fehlt dann ein korrektes Syntaxhighlighting.

Ein Beispiel für eine ähnliche Problemstellung wurde in HttpUtils bei den nonblocking Funtkionen bereits hervorragend umgesetzt.
Man kann den Callback entweder als Zeiger auf eine extra Funktion (bei viel Code) angegeben, oder eben eine anonyme Sub direkt Inline schreiben:

HttpUtils_NonblockingGet({
url         => "bla",
hash        => $hash,
callback    => sub() {
Log 1, "Ich bin ein Inline-Callback;
}
});

Ich träume jetzt von etwas Ähnlichem für NoneBlocking Sleeps nach dem Schema:
delay(5, sub() {
  Log 1, "Ich bin ein 5 Sekunden verzögerter Befehl;
}

Gäbe es weitere Interessenten an so etwas?
Und wäre es überhaupt Möglich das ohne extreme Änderungen an den Innereien von Fhem?
Weiß nicht wie die Timer und ihre Callbacks intern gespeichert werden und ob es einen Grund gibt, warum das bei HTTPUtils keine Problem machen könnte,
bei Internen Timern hingegen schon.
« Letzte Änderung: 09 Februar 2018, 22:08:24 von Thyraz »
Fhem und MariaDB auf NUC6i5SYH in Proxmox Container (Ubuntu)
Zwave, Lacrosse, Hue, Harmony, Solo4k, LaMetric, ...

Offline herrmannj

  • Global Moderator
  • Hero Member
  • ****
  • Beiträge: 4659
gute Idee. Als "at" eingecheckt ;)
https://fhem.de/commandref_DE.html#at
define a5 at +00:00:05 {Log 1, 'Test'}
smartVisu mit fronthem, einiges an HM, RFXTRX, Oregon, CUL, Homeeasy, ganz viele LED + Diverse
Gefällt mir Gefällt mir x 2 Liste anzeigen

Offline Thyraz

  • Sr. Member
  • ****
  • Beiträge: 728
Hm.. irgendwie schon, irgendwie "jein". ;)

Die "at"s landen dann ja als Modulinstanzen sichtbar in Fhem.
Soll sowas wirklich im Quellcode eines offiziellen Fhem Modul stehen?  :o

Könnte mir vorstellen, die Begeisterung der User wäre verhalten, wenn da andauernd "at"s auftauchen und verschwinden.

Das FHEM Sleep wird ja nicht umsonst gern als unbenanntes at bezeichnet.
Fhem und MariaDB auf NUC6i5SYH in Proxmox Container (Ubuntu)
Zwave, Lacrosse, Hue, Harmony, Solo4k, LaMetric, ...

Offline CoolTux

  • Developer
  • Hero Member
  • ****
  • Beiträge: 15233
Wenn es Dir um die Anwendung in einem Modul geht und da um Verzögerung, dann erzähl Mal was Du genau machen willst. Es gibt viele Wege und man muss ja nicht unbedingt verzögern.
Du kannst mit NotifyFn arbeiten oder auch mit einer Queue.
Kommt halt immer auf die Anforderung an.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.me/MOldenburg
Mein GitHub: https://github.com/LeonGaultier
kein Support für cfg Editierer
Hilfreich Hilfreich x 1 Liste anzeigen

Offline Thorsten Pferdekaemper

  • Developer
  • Hero Member
  • ****
  • Beiträge: 4684
  • Finger weg von der fhem.cfg
Genauer gesagt, dass man bei InternalTimer einen Funktionsname statt einen Zeiger oder alternativ eine anonyme Sub übergibt.
Hast Du das ausprobiert? Ich übergebe zumindest manchmal Funktionszeiger und das geht. Ich würde vermuten, dass das auch mit anonymen Subs funktioniert.
Wenn man sich mal das Coding in fhem.pl anschaut, dann sehe ich nicht, warum das nicht gehen sollte.
Gruß,
   Thorsten
RasPi
Heizkessel-Steuerung per Arduino und HTTPMOD
und einen Haufen Homematic (Wired)
Zustimmung Zustimmung x 1 Informativ Informativ x 1 Liste anzeigen

Offline Thyraz

  • Sr. Member
  • ****
  • Beiträge: 728
Nein, habe ich tatsächlich nicht...

Da es in der Doku "Der Name der Funktion als Zeichenkette" heißt,
bin ich nicht auf die Idee gekommen, dass dies funktionieren könnte.

Es geht aber tatsächlich.
Und wir bekommen als nette Beigabe die Fähigkeit von Closures, dass sie die Variablen aus ihrem umgebenden Scope an sich binden. :)

my $text = "This text is declared before the delay";

InternalTimer( gettimeofday() + 5, sub() {
    Log 1, "$text";
}, undef);

Man hat ja meist mehrere Variablen die man dem InternalTimer übergeben muss, wofür es den arg Parameter gibt.
Da man aber nur einen Parameter übergeben kann, muss man oft erstmal eine Hash-Ref erstellen.
Das ist dann ja auch wieder zusätzlicher Code.

Kann man sich dank Closure sparen und direkt auf die umgebenden Variablen zugreifen.

Danke für die Rückmeldungen, jetzt muss ich hier erstmal ein wenig Code Refactoring betreiben.  :P
Fhem und MariaDB auf NUC6i5SYH in Proxmox Container (Ubuntu)
Zwave, Lacrosse, Hue, Harmony, Solo4k, LaMetric, ...

Offline Thorsten Pferdekaemper

  • Developer
  • Hero Member
  • ****
  • Beiträge: 4684
  • Finger weg von der fhem.cfg
Hi,
so etwas in der Art müsste auch gehen:
InternalTimer( gettimeofday() + 5, sub() {
    my ($arg1,$arg2,$arg3) = @{$_[0]};
    # mach was mit $arg1 etc.
}, ["abc",42,6*9]);
Gruß,
   Thorsten
RasPi
Heizkessel-Steuerung per Arduino und HTTPMOD
und einen Haufen Homematic (Wired)

Offline Thyraz

  • Sr. Member
  • ****
  • Beiträge: 728
Klaro, ob Hash-Ref oder Array ist ja erstmal egal.

Aber du hast mehr Tipparbeit durch die Wertübergabe und musst die Werte in der Funktion ja auch wieder aufdröseln.
Ist bei einer Closure unnötig, da du direkt auf die äußeren Variablen zugreifen kannst.

Die Zuweisung der Variable $text in meinem Code war ja nur beispielhaft.
Normal geht es ja um den Zugriff auf bereits bestehende Variablen des äußeren Contexts die dort sowieso bestehen.

Der Code beschränkt sich also auf
InternalTimer( gettimeofday() + 5, sub() {
    Log 1, "$textFromOuterScope $anotherVarFromOutside ...";
}, undef);

Was minimalistischer und einfacher zu lesen ist.
« Letzte Änderung: 09 Februar 2018, 22:52:24 von Thyraz »
Fhem und MariaDB auf NUC6i5SYH in Proxmox Container (Ubuntu)
Zwave, Lacrosse, Hue, Harmony, Solo4k, LaMetric, ...

Offline herrmannj

  • Global Moderator
  • Hero Member
  • ****
  • Beiträge: 4659
Und wir bekommen als nette Beigabe die Fähigkeit von Closures, dass sie die Variablen aus ihrem umgebenden Scope an sich binden. :)
Achtung! Ideale Quelle für memory leaks

Solange der Timer läuft bleiben die vars im (anonymen) scope. Wenn Du jetzt (direkt oder indirekt) "von innen nach aussen" referenzierst bildet sich eine loop und die Speicher bleibt auf immer und ewig gebunden. Bei zyklischen timern dann immer wieder.
smartVisu mit fronthem, einiges an HM, RFXTRX, Oregon, CUL, Homeeasy, ganz viele LED + Diverse
Informativ Informativ x 2 Liste anzeigen

Offline ToKa

  • Full Member
  • ***
  • Beiträge: 300
Hallo zusammen,

habe jetzt InternalTimer so wie hier beschrieben in meiner myUtils im Einsatz. Das funktioniert wunderbar.

Da ich diese interne Funktion bislang nicht kannte, bin ich mir jetzt aber unsicher, ob man jeden Timer - auch wenn er abgelaufen ist - durch ein RemoveInternalTimer wieder löschen muss?

Beste Grüße
Torsten
RaspberryPi3 mit RaZberry2
Fibaro: FGWPE/F-101 Switch & FIBARO System FGWPE/F Wall Plug Gen5, FGSD002 Smoke Sensor
GreenWave: PowerNode 1 port
EUROtronic: SPIRIT Wall Radiator Thermostat Valve Control
Zipato Bulb 2

Offline CoolTux

  • Developer
  • Hero Member
  • ****
  • Beiträge: 15233
Nein muss man nicht. Wenn er abgelaufen ist wird er auch entfernt.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.me/MOldenburg
Mein GitHub: https://github.com/LeonGaultier
kein Support für cfg Editierer

Offline ToKa

  • Full Member
  • ***
  • Beiträge: 300
Super und danke für die schnelle Rückmeldung!
RaspberryPi3 mit RaZberry2
Fibaro: FGWPE/F-101 Switch & FIBARO System FGWPE/F Wall Plug Gen5, FGSD002 Smoke Sensor
GreenWave: PowerNode 1 port
EUROtronic: SPIRIT Wall Radiator Thermostat Valve Control
Zipato Bulb 2