Autor Thema: Nicht blockierendes sleep innerhalb eines Moduls?  (Gelesen 241 mal)

Offline mumpitzstuff

  • Full Member
  • ***
  • Beiträge: 466
Nicht blockierendes sleep innerhalb eines Moduls?
« am: 07 Dezember 2017, 12:47:56 »
Gibts die Möglichkeit innerhalb eines Moduls ein nicht blockierendes Sleep zu verwenden? Wenn ja wie? Einfach nur sleep(1) im Code? Mir ist das nicht so ganz klar, weil FHEM ein nicht blockierendes Sleep integriert hat, das von Perl aber gleich heißt (das ist blockierend). Was wird jetzt verwendet wenn man einfach sleep(1) ins Modul rein schreibt?
Welche Möglichkeiten gibt es sonst noch, ohne über zusätzliche Timer und Funktionen den Code zerpflücken zu müssen (sollte immer non blocking sein)?

Hintergrund:
Ich muss ziemlich viele Requests an einen Server stellen, überlaste diesen jedoch, wenn ich alle auf einmal raus ballere. Ich will das deshalb etwas zeitlich entzerren. Vollständig serialisieren will ich das nicht, das würde zu viel Zeit kosten.

Offline justme1968

  • Developer
  • Hero Member
  • ****
  • Beiträge: 17016
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #1 am: 07 Dezember 2017, 13:01:28 »
nein. mit sleep geht das nicht.

falls es http ist: die httputils im nonblocking mode funktionieren gut. wenn es dir rein seriell zu langsam geht kannst du ja mehr als eine anfrage auf einmal absetzen und dann immer wenn eine zurück kommt eine weitere hinterher schieben.

wenn es ein socket ist kannst du non blocking io verwenden und es in die select loop einhängen und reagieren wenn du wieder schreiben kannst.

bist du sicher das rein seriell zu langsam ist? wenn’s er server schon in die knie geht ist der limitierende faktor vermutlich nicht die netzwerk round trip zeit.
FHEM5.4,DS1512+,2xCULv3,DS9490R,HMLAN,2xRasPi
CUL_HM:HM-LC-Bl1PBU-FM,HM-LC-Sw1PBU-FM,HM-SEC-MDIR,HM-SEC-RHS
HUEBridge,HUEDevice:LCT001,LLC001,LLC006,LWL001
OWDevice:DS1420,DS18B20,DS2406,DS2423
FS20:fs20as4,fs20bs,fs20di
AKCP:THS01,WS15
CUL_WS:S300TH

Online DS_Starter

  • Developer
  • Hero Member
  • ****
  • Beiträge: 1927
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #2 am: 07 Dezember 2017, 13:10:12 »
Eine Idee/Anregung hätte ich noch unter Benutzung von BlockingCall (Blocking.pm).
Du verzweigst damit in einen nebenlaufenden Prozess und arbeitest dort alles ab. Dort kannst du auch mit einem blockierenden perl sleep arbeiten.
Das tut nichts.
Nachteil ist, dass du Auswertungen, Variablen, Hash-Werte usw. erst wieder an den Hauptprozess übergeben kannst wenn der BlockingCall zu Ende ist und die FinishFn aufgerufen wird.
ESXi 6.5 auf NUC6i5SYH mit FHEM Gastsystemen auf Debian 8 64 Bit  (Jessie) & Synology iSCSI-LUNs,
DbLog/DbRep mit MariaDB auf Synology 415+,
Homematic, IT, FS20, Cams in Synology Surveillance Station (SSCAM), CUL 433, CUL 868, HM-CFG-LAN

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 17436
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #3 am: 07 Dezember 2017, 13:12:42 »
Zitat
Nachteil ist, dass du Auswertungen, Variablen, Hash-Werte usw. erst wieder an den Hauptprozess übergeben kannst wenn der BlockingCall zu Ende ist und die FinishFn aufgerufen wird.
Das geht auch vorher mit BlockingInformParent, als Beispiel siehe update_Log2Event in 98_update.pm

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 13697
  • Das "S" in "IoT" steht für "Security"
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #4 am: 07 Dezember 2017, 13:16:49 »
Mir ist das nicht so ganz klar, weil FHEM ein nicht blockierendes Sleep integriert hat, das von Perl aber gleich heißt

Wenn Du in einem Modul sleep() verwendest, wird immer die perl Funktion verwendet.

Das sleep in FHEM ist ein FHEM-Befehl und deshalb nicht unter diesem Namen als Funktion verfügbar.
-----------------------
Nächster Hamburg-Stammtisch: 23.03.2018

Online DS_Starter

  • Developer
  • Hero Member
  • ****
  • Beiträge: 1927
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #5 am: 07 Dezember 2017, 13:21:54 »
Zitat
Das geht auch vorher mit BlockingInformParent, als Beispiel siehe update_Log2Event in 98_update.pm

Ah... interessant. Danke für die Info Rudi. Kann ich gut gebrauchen.

Grüße
Heiko
ESXi 6.5 auf NUC6i5SYH mit FHEM Gastsystemen auf Debian 8 64 Bit  (Jessie) & Synology iSCSI-LUNs,
DbLog/DbRep mit MariaDB auf Synology 415+,
Homematic, IT, FS20, Cams in Synology Surveillance Station (SSCAM), CUL 433, CUL 868, HM-CFG-LAN

Offline Wzut

  • Developer
  • Hero Member
  • ****
  • Beiträge: 1643
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #6 am: 07 Dezember 2017, 14:28:30 »
Danke für die Info Rudi. Kann ich gut gebrauchen.
@DS_Starter , mach mal im FHEM Unterordner ein grep InformParent *.pm
Ausser Rudi , HCS und Tobias scheint das bisher auch kein anderer Modulautor auf dem Radar zu haben :)
( Ich selbst will da noch 2017 mit zwei Modulen dazu .... )
Maintainer der Module: MPD, EDIPLUG, UbiquitiMP, UbiquitiOut, SIP

Online DS_Starter

  • Developer
  • Hero Member
  • ****
  • Beiträge: 1927
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #7 am: 07 Dezember 2017, 14:39:06 »
Zitat
Ausser Rudi , HCS und Tobias scheint das bisher auch kein anderer Modulautor auf dem Radar zu haben :)
Stimmt, bin zwar immer mal wieder darüber gestolpert, aber richtig wahrgenommen/verarbeitet habe ich es bisher nicht.
Bis jetzt war ich auch ganz gut ohne diese Möglichkeit ausgekommen, aber letztens bin ich bei einer Aufgabenstellung ohne dieses Feature nicht vorwärts gekommen und habe andere Verrenkungen zur Lösung des Problems gemacht.
Mir ist das einfach nicht eingefallen .... werde mir die Sache nochmal unter diesem Aspekt neu vornehmen ....
ESXi 6.5 auf NUC6i5SYH mit FHEM Gastsystemen auf Debian 8 64 Bit  (Jessie) & Synology iSCSI-LUNs,
DbLog/DbRep mit MariaDB auf Synology 415+,
Homematic, IT, FS20, Cams in Synology Surveillance Station (SSCAM), CUL 433, CUL 868, HM-CFG-LAN

Offline mumpitzstuff

  • Full Member
  • ***
  • Beiträge: 466
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #8 am: 07 Dezember 2017, 15:03:19 »
Das Problem ist leider nicht so trivial wie es aussieht.

Es handelt sich hierbei um ein WLAN Radio, bei dem man diverse Informationen immer wieder abholen muss (polling). Den Ansatz BlockingCall zu verwenden hatte ich schon mal, aber dann passiert folgendes:

Request
Warten
Antwort
Request
Warten
Antwort

Insgesamt dauert das zu lang bei bisher rund 30 Anfragen an das Radio. Ob das funktionieren würde aus einem BlockingCall heraus asynchron mit CallBacks zu arbeiten, weiß ich nicht, das Thema war mir zu heiß. Wenn mir jemand sagt, dass das geht, dann versuche ich aber gern auch das noch mal.
Ich habe deshalb die Non Blocking Funktionen der httputils verwendet und im ersten Schritt einfach in der Update Funktion 30 Requests ans Radio rausgeballert. Nach etwa 20 Antworten bekomme ich für die restlichen 10 entweder timeout oder leere Daten.
Um das zu umgehen kann ich jetzt entweder zwischen den Requests etwas warten und damit dem Radio Zeit geben bereits geschickte Requests zu beantworten. Super wäre ein sleep in irgend einer Art gewesen, weil sich das nahtlos in den bestehenden Code integrieren lassen würde. Da das nicht geht, kann ich nur durch die Callbacks getriggert das Senden der Pakete starten. Und jetzt kommt das ABER: Die Reihenfolge der Antworten ist unbekannt. Es passiert also folgendes:

Request 1
Request 2
Request 3
Warten
Antwort 3
Antwort 1
Antwort 2

Ich kann damit also nicht sagen: wenn du die Antwort von Request 3 empfangen hast, dann starte die nächsten 3 Requests. Schlussendlich bedeutet dass, ich muss mir den Status aller 3 Requests merken und wenn alle 3 angekommen sind, dann darf ich erst die nächsten 3 Requests schicken. Und da wird die Handhabung dann irgendwie extrem kacke und der Ansatz fliegt deshalb erst mal raus.

Die zweite Idee die ich habe ist:

timer1 -> Update1()
timer2 = timer1 + 2 -> Update2()
timer3 = timer2 + 2 -> Update3()

Update1()
Update2()
Update3()

Dann sind die Update Pakete zeitlich voneinander etwas entkoppelt und das Radio sollte genug Zeit haben die Requests zu beantworten. Vom Code her immer noch bescheiden, aber wahrscheinlich robuster als Version 1.
« Letzte Änderung: 07 Dezember 2017, 15:05:25 von mumpitzstuff »

Online CoolTux

  • Developer
  • Hero Member
  • ****
  • Beiträge: 12180
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #9 am: 07 Dezember 2017, 15:51:36 »
Mach doch eine Queue. Schau dir mal das hier an

 https://github.com/LeonGaultier/fhem-TeslaPowerwall2AC?files=1
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

Offline mumpitzstuff

  • Full Member
  • ***
  • Beiträge: 466
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #10 am: 07 Dezember 2017, 16:30:58 »
Idee gefällt mir gut.

Update (timer alle x Sekunden (mindestens 20)) -> 30 Requests -> Queue

Queue (timer jede Sekunde) -> 5 Requests los schicken und per Callback verarbeiten

Ich denke das werde ich so angehen. Danke!

Online CoolTux

  • Developer
  • Hero Member
  • ****
  • Beiträge: 12180
Antw:Nicht blockierendes sleep innerhalb eines Moduls?
« Antwort #11 am: 07 Dezember 2017, 16:43:11 »
Gern geschehen.  :)
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