Modul SubThread für Threads in FHEM

Begonnen von zap, 01 Januar 2017, 14:45:01

Vorheriges Thema - Nächstes Thema

justme1968

warum ist der prozess während der weitergabe blockiert?

der prozess schreib ein häppchen oder so viel wie möglich zum parent und kann sofort weiter auf die daten der ccu warten. d.h. so wie joerg  schreibt: eine einzige perl var an die die ccu daten hinten angehängt und am anfang abgeschnitten und zum parent geschickt wird sollte als buffer völlig reichen.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

herrmannj

#16
ich vermute mal (und das ist nicht böse gemeint) dass das Problem woanders liegt. Ich vermute das der socket zum parent blockierend ist. Wenn der non-blocking ist (wäre) dann würde das von Dir beschriebene Verhalten nicht auftreten.

Jetzt kann man da beliebig forks/threads/komplett separate Prozesse drum legen - das Problem bleibt. Wenn der Socket non-blocking ist braucht man hingegen auch den sub-prozess nicht mehr. Der sub-prozess ist die richtige Medizin wenn viel CPU ZEIT* am Stück benötigt wird. Für IO Prozesse ist er ohnehin das falsche Mittel.

Für IO Prozesse ist das Mittel der Wahl immer SELECT / NON BLOCKING SOCKETS. Die sorgen (auf OS Ebene) dafür das nur soviel in den Socket (pipe etc) geschrieben wird wie der aufnehmen kann. Außerdem wird per select gemeldet wenn der socket wieder Daten entgegennehmen kann weil er auf der anderen Seite welche losgeworden ist.

Das vergrößern der IO buffer hilft dementsprechend auch nur scheinbar. Es passt dann zwar mehr rein, irgendwann ist der buffer aber trotzdem voll. Die Größe des IO buffers spielt daher auch keine relevante Rolle weil Du ohnehin etwas brauchst (die perl var) um den Rest dort zwischenzuspeichern.

Wie gesagt, bitte nicht falsch verstehen. Ich vermute das Du das Problem an der falschen Stelle anpackst. Damit wäre es möglich die Komplexität - damit die Fehlerquellen - beliebig hoch zu treiben ohne die eigentliche Ursache wirklich anzupacken.

vg
joerg

(*) edith:
oder ich ein ganz genaues Timing benötige.

zap

Zitat von: justme1968 am 02 Januar 2017, 12:24:25
warum ist der prozess während der weitergabe blockiert?

der prozess schreib ein häppchen oder so viel wie möglich zum parent und kann sofort weiter auf die daten der ccu warten. d.h. so wie joerg  schreibt: eine einzige perl var an die die ccu daten hinten angehängt und am anfang abgeschnitten und zum parent geschickt wird sollte als buffer völlig reichen.

Und was macht der Subprozess mit den verbliebenen Daten in var, wenn keine weiteren mehr von der cCU kommen? Dann fehlt quasi der Trigger , um den Rest zu schreiben.

- 10 Byte werden empfangen
- davon werden 5 Byte an den Parent geschickt und 5 bleiben im Puffer
- Subprozess geht wieder in seine Accept Schleife und wartet auf Daten der CCU

Die verbleibenden 5 Byte werden also irgendwann geschrieben, aber nicht unbedingt zeitnah.

@hermannj: der Subprozess wird für den RPC Server gebraucht. Der läuft in einem Listen/Accept Loop und ruft für jede eingehende Verbindung eine zuvor registrierte Callback Funktion auf. Und solange diese Funktion nicht zurück kehrt, nimmt er keine neuen Verbindungen an

Aber die Diskussion hier war insofern hilfreich, dass ich ein paar neue Ideen bekommen habe.
2xCCU3, Fenster, Rollläden, Themostate, Stromzähler, Steckdosen ...)
Entwicklung: FHEM auf AMD NUC (Ubuntu)
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: FULLY, Meteohub, HMCCU, AndroidDB

justme1968

auch hier hilft select. das socket zum schreiben kann genau so in die selectlist eingetragen werden. wenn wieder geschrieben werden kann meldet sich das select.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

herrmannj

#19
das habe ich sehr wohl verstanden :)  @zap (überschnitten mit andre post)

Tipp: schau Dir den gesamten Komplex non-blocking IO mal genau an. Der macht genau Alles was Du beschreibst und suchst.
https://www.google.com/search?q=non-blocking+IO#q=non+blocking+io+perl

ZitatUnd was macht der Subprozess mit den verbliebenen Daten in var, wenn keine weiteren mehr von der cCU kommen? Dann fehlt quasi der Trigger , um den Rest zu schreiben.

- 10 Byte werden empfangen
- davon werden 5 Byte an den Parent geschickt und 5 bleiben im Puffer
- Subprozess geht wieder in seine Accept Schleife und wartet auf Daten der CCU
eben nicht:

die listen/accept loop fliegt raus. Fhem macht alles das bereits in der select loop.

Der socket der auf das listen wartet wird im %selectlist registiriert.
Der socket der Daten vom RPC holt wird in der %selectlist registirert
Der socket der an den Parent schickt (Du ahnst es :) ) ... wird in der %selectlist registriert.

Und nach einige andere ...

Und egal welcher von denen jetzt "zuckt", die selectloop meldet Dir das.

Wenn also eine Aktion auf dem Socket stattfindet wo Du Dein listen hast und wo Du accepten möchtest ruft fhem von sich aus die sub auf die Du angibst. Dort fährst Du den accept *und machst den socket sofort ebenfalls non-blocking* ! Danach ebenfalls in der %selectlist registirieren.

Fhem meldet Dir auch *während* (!!!) Du auf den connect evtl clients wartest das der parent Daten entgegennehmen kann. Kannst Du direkt (während des wartens auf connect!) die Daten raus schicken.

Vertrau mir, Du versuchst gerade eine Schraube mit dem Hammer in die wand zu bekommen, Du benötigst aber Bohrer, Dübel und Schraubenzieher. ;)

vg
joerg

zap

#20
Zitat von: herrmannj am 02 Januar 2017, 14:55:17
Vertrau mir, Du versuchst gerade eine Schraube mit dem Hammer in die wand zu bekommen, Du benötigst aber Bohrer, Dübel und Schraubenzieher. ;)

Danke  :D  Ich schaue mir das alles mal an. Allerdings befürchte ich, dass ich - wenn ich nur den selectlist Mechanismus verwende - die RPC Server Logik aus dem Modul RPC::XML::Server nachbauen muss.

Und um diese ganzen Sockets zu registrieren, muss ich wohl ähnlich wie im Plex-Modul hidden Devices definieren, da ja jedes Device nur einen Filedescriptor haben kann.

Wenn das alles sich über die selectlist abbilden lässt, braucht es ja überhaupt keine Hintergrundprozesse mehr in FHEM. Dann hätte ich mir die Nervenschlacht mit SubProcess.pm vor einigen Monaten sparen können.  Das sollte man auch den Modulentwicklern mal mitteilen, die jetzt Subprozesse und Threads verwenden.

Ok, streiche das oben. Ich nutze also doch einen SubProzess. Allerdings nutzt der SubProzess ebenfalls den selectlist Mechanismus. Nach dem 2. Lesen deines Posts habe ich es glaube ich kapiert. Allerdings ohne SubProcess.pm, da dort alles in OnRun() abläuft und der FHEM Loop nie zum Zug kommt. Also ein simpler fork() bei dem der Child Prozess sofort zurückkehrt.

Also erst mal kein Multithreading in FHEM. Ich versuche es mit SubProzess. Blöd ist nur das RPC Handling.
2xCCU3, Fenster, Rollläden, Themostate, Stromzähler, Steckdosen ...)
Entwicklung: FHEM auf AMD NUC (Ubuntu)
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: FULLY, Meteohub, HMCCU, AndroidDB

justme1968

pro socket brauchst du einen minimalen hash den du in die select list hängst und der alle nötigen dinge enthält um aus der readFn die durch das select aufgerufen wird rückwärts an die für dich nötigen daten zu kommen. d.h. in den hash steckst du alles an kontext der für diese eine verbindung nötig ist.

wenn du nur einen socket hast kannst du dazu direkt den device hash selber verwenden. wenn es mehrere sockets sind brauchst du eigene hashes. der device hash kümmert sich dann meist um das socket für die eingehenden verbindungen. nach dem accept legt er dann der hash für die jeweilige verbindung an und hängt ihn in die  selectlist. (es ist übrigens nicht zwingend nötig das diese hashes von selben TYPE sind wie das haupt device. je nach anwendungsfall kann man hier spielen und über einen eigenen TYPE auch unterschiedliche readFn für unterschiedliche socket arten umsetzen)

das mit den versteckten hashes ist im prinzip bei allen devices so die verbindungen von aussen annehmen. z.b. auch fhemweb, telnet, ...

plex ist noch etwas spezieller da es mindestens eine hand voll sockets für die client und server broadcast und multicast discovery braucht, zusätzlich noch verbindungen pro client für die timeline plus eine websocket verbindung pro server.


schau mal ob es nicht sogar ohne extra prozess geht. für das reine handling mehrere sockets braucht es das nämlich noch nicht. und dann sparst du dir auch das komplette parent/child handling. wenn es tatsächlich noch timing probleme gibt weil etwas anderes in fhem zu viel zeit braucht kannst du das ganze immer noch per Blocking oder SubProcess auslagern.

viel spass beim basteln :)
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

zap

Als Nachtrag: habe jetzt mal versucht, dem FHEM select Loop den FD eines mit Open() geöffneten Strings unterzujubeln. War keine gute Idee. Das hat FHEM aber sowas von zerlegt :-)

Wollte über das Schreiben in diesen String den Aufruf von X_Read zu triggern.
2xCCU3, Fenster, Rollläden, Themostate, Stromzähler, Steckdosen ...)
Entwicklung: FHEM auf AMD NUC (Ubuntu)
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: FULLY, Meteohub, HMCCU, AndroidDB

justme1968

spontan würde ich sagen das könnte daran liegen das so ein FD auf einen string kein echter fd auf os ebene ist (so wie files, pieps und sockels) sondern eine perl besonderheit und sich deshalb nicht mit select verträgt.

der fd zum testen sollte vermutlich auch zwei 'enden' haben. einen zum schreiben und einen zum lesen an dem die daten ankommen. ich weiß gerade nicht ob das für normale files zutrifft. für den string ziemlich sicher nicht.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

ZitatFD eines mit Open() geöffneten Strings
Was ist das eigentlich? Kann irgendwie nichts Sinnvolles darunter vorstellen. Dem Select kann man unter Linux/OSX mW alles geben, was zu einem OS-Filedescriptor zugeordnet wird. Unter Windows geht das nur fuer Netzwerk-FD, da MS vor 20+ Jahren beim Kopieren des Netzwerk-Kodes von BSD select zwar uebernommen hat, aber nicht fuer den Rest (Files, Serielle Schnittstellen, etc) implementiert hat.

justme1968

mit neueren perl versionen kann man strings (memory) und auch here documents wie files öffnen.

aber wie oben geschrieben tippe ich mal das dies keine os files sind sondern irgend eine perl emulation die sich dann auch nicht mit select verträgt.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

zap

Zitat von: rudolfkoenig am 04 Januar 2017, 09:30:53
Was ist das eigentlich? Kann irgendwie nichts Sinnvolles darunter vorstellen. Dem Select kann man unter Linux/OSX mW alles geben, was zu einem OS-Filedescriptor zugeordnet wird. Unter Windows geht das nur fuer Netzwerk-FD, da MS vor 20+ Jahren beim Kopieren des Netzwerk-Kodes von BSD select zwar uebernommen hat, aber nicht fuer den Rest (Files, Serielle Schnittstellen, etc) implementiert hat.

Sowas (ab Perl 5.8  ):


my $string = '';
open($fh, "+<", \$string);
print $fh "Content for String";
my $c = <$fh>;


http://docstore.mik.ua/orelly/perl4/cook/ch08_24.htm

Aber Haken dran. Ist nicht so wichtig. War eh ne blöde Idee.
2xCCU3, Fenster, Rollläden, Themostate, Stromzähler, Steckdosen ...)
Entwicklung: FHEM auf AMD NUC (Ubuntu)
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: FULLY, Meteohub, HMCCU, AndroidDB