Threads mit While-Loop + Datenaustausch der Threads mit tkinter.Fenster

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Speedy77
User
Beiträge: 18
Registriert: Samstag 13. März 2021, 13:14

Hallo Profis,

habe jetzt schon einiges gelesen (hier im Forum), herausgefunden :?: und probiert. Jetzt bin ich mir nicht ganz sicher ob mein aktuell gestartete Umsetzung zum Ziel kommen kann.

Vorhaben:
  1. starten eines Fensters (tkinter)
    1. hier wird alles in Klassen gesammelt (siehe 2. und 3.)
  • in der __init__ werden dann, auf mehrere Klassen und Dateien verteilt, diverse Threads gestartet (aktuell sind es 4)
    1. alle dieses Threads haben grundsätzlich den gleichen Aufbau:
      • sie sind ein Klassenobjekt
      • sie sind in sich geschlossen und eigenständig lauffähig
      • sie binhalten nur eigen benötigte Funktionen
      • am Ende in der Hauptfunktion springen sie in eine While-Schleife (dauerhaft) und lesen Daten aus verschiedenen System
      • aktuell werden diese Daten auf der Konsole geschrieben (print())
  • Es gibt eine übergeordnete Klasse die die Threads aufnimmt
    1. hier können die threads gestartet und gestopt werden
      • zum beispiel wenn ein thread auf grund eines Fehlers beendet wurde --> Logging --> Neustart
Die dauerhaft laufenden Threads sollen nun die Daten (die aktuell noch als Text auf die Konsole geschriegen werden) in eine übergeordnete Variable schreiben:

Code: Alles auswählen

class HWnd(tk.Tk):
    def __init__(self):
        tk.TK.__init__(self)
        self._myvars = myvar_class
        self._threads = thread_class(self)
        ...
        self.start_autostart()             'Hier werden jetzt alle Threads gestartet
Datei: cls_glob_var.py

Code: Alles auswählen

class myvar_class:
    def __init__(self):
        self.Variable1
Das Hwnd soll nun die in _myvars gespeicherten Werte in Labels, Textboxen, Listboxen, etc. darstellen und einlesen. Änderungen sollen dann wiederum in einigen Threads beachtet und darauf reagiert werden.

Ist dies in diesem Aufbau überhaupt möglich --> Dadenaustausch zwischen HWnd und dauerhaft laufenden Threads und zurück?

noch als Info: der "gesamte" Code liegt aktuell in 70 Datein in Unterverzeichnissen vor ... ist also schwer zu posten :?

vielen Dank im Vorraus für eure Hilfe
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Speedy77: Wenn die 70 Dateien vom Namen alle so aussehen wie `cls_glob_var` und einzelne Klassen mit Klassen wie `myvar_class` enthalten, dann läuft da was falsch. Dateien sind Module und Module sind dazu da um zusammengehörende Funktionen und Klassen zusammenzufassen.

`class` hat in einem Klassennamen nichts zu suchen, sofern es sich nicht tatsächlich um eine Klasse in der Problemdomäne handelt. Das es sich um eine Klasse handelt sieht man ja schon am Namen, denn der fängt mit einem Grossbuchstaben an.

Der Präfix `my` macht keinen Sinn wenn es nicht auch ein `our_*` oder `their_*` gibt gegen den sich das `my_*` abgrenzen würde.

`HWnd` ist auch kein sinnvoller Name. Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen.

Von `myvar_class` wird da anscheinend gar kein Exemplar erstellt. Und wenn Objekte sich direkt gegenseitig kennen, ist oft die Frage ob da sauber getrennt wurde. Eine Klasse die Threads verwaltet sollte eigentlich nicht direkt etwas über GUI/das Hauptfenster wissen müssen.

Normalerweise schreibt man die Programmlogik unabhängig von der GUI und übergibt das dann der GUI als Argument, damit man das auch ohne GUI testen und verwenden kann.

Von Threads aus darf man in der Regel nichts an der GUI verändern. Bei Tk ist es üblich von Threads aus über eine Queue mit der GUI-Hauptschleife zu kommunizieren indem dort über die `after()`-Methode regelmässig die Queue abgefragt wird.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Speedy77
User
Beiträge: 18
Registriert: Samstag 13. März 2021, 13:14

Hallo __blackjack__

erst einmal Danke für die schnelle Antwort
@Speedy77: Wenn die 70 Dateien vom Namen alle so aussehen wie `cls_glob_var` und einzelne Klassen mit Klassen wie `myvar_class` enthalten, dann läuft da was falsch. Dateien sind Module und Module sind dazu da um zusammengehörende Funktionen und Klassen zusammenzufassen.
du hast natürlich mit deinen Aussagen recht und die Dateien und Klassen heisen nicht alle so oder sehen so aus. Die Darstellung diente nur zum Verständnis

Ich gehe also auf die regelkonforme Programmierung und Konventions nicht tiefer ein da das stimmt und ich DIr zu 100% Recht gebe.
Von `myvar_class` wird da anscheinend gar kein Exemplar erstellt. Und wenn Objekte sich direkt gegenseitig kennen, ist oft die Frage ob da sauber getrennt wurde. Eine Klasse die Threads verwaltet sollte eigentlich nicht direkt etwas über GUI/das Hauptfenster wissen müssen.
Wenn Du hier auf die vergessenen "()" ind der Zeile "self._myvars = myvar_class" anspielst... OK... muss ich DIr recht geben... habe ich vergessen
Das gegenseitige Kennen könnte ich auch ausmerzen... Steht hier aber auch nicht zur Debatte...
Normalerweise schreibt man die Programmlogik unabhängig von der GUI und übergibt das dann der GUI als Argument, damit man das auch ohne GUI testen und verwenden kann.
Das ist schon mal ein guter Hinweis für mich... Hättest Du mal noch ein zwei Begriffe mit denen Ich mich Beschäftigen müsste oder die mir bei Miss Google einigen Antworten liefern :D
Von Threads aus darf man in der Regel nichts an der GUI verändern. Bei Tk ist es üblich von Threads aus über eine Queue mit der GUI-Hauptschleife zu kommunizieren indem dort über die `after()`-Methode regelmässig die Queue abgefragt wird.
Was meinst Du mit Verändern??? ich gebe einem Entry eine Textvariable die ich im Thread anpasse --> Neuer Wert im Entry ???
Das mit dem after() ist ja mein Problem.... alle meine Threads sind Eigenläufer und laufen nach dem Start intern in einer While-Schleife bis ich sie mit Thread-Klasse._stop_() beende. Der Thread läuft immer...
Das mit den Queue werde ich mir anschauen und mich zurück melden...
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Irgend einen Sinn wird es schon gehabt haben, dass Du Dein Modul cls_glob_var genannt hast, und das klingt sehr danach, als ob Du eine Klasse mit lauter globalen Variablen definiert hättest. Globale Variablen sind schlecht, besonders im Kontext von Threads. Jede Klasser, jeder Thread hat seine eigenen Variablen, die unabhängig voneinander sind.

Threads kommunizieren mit anderen Programmteilen immer über Queues oder ähnliche Methoden. Und auch das Beenden eines Threads geht nur kooperativ, also in dem das Hauptprogramm dem Thread ein Signal sendet "bitte beende Dich".

Und das mit dem Verändern ist genauso gemeint, wie es geschrieben steht: MAN DARF DIE GUI NICHT ÄNDERN! Dazu gibt es in diesem Forum zig Beiträge, die genau dieses Thema behandeln.
Klar sind Threads "Eigenläufer" sonst bräuchte man sie nicht, aber sie kommunizieren mit der Außenwelt, in dem sie Informationen über eine Queue empfangen und ihre Ergebnisse wieder in eine Queue stecken. Wer am anderen Ende sitzt, ist dem Thread egal; das kann eine Funktion in der GUI sein, die regelmäßig über after aufgerufen wird und schaut, ob eine Nachricht über die Queue angekommen ist, und dann entsprechend darauf reagiert, in dem sie z.B. ein Entry-Feld anpasst.

Aus Deinen Code-Fragmenten kann man nichts herauslesen, außer dass die Namen der Klassen darauf hindeuten, dass die ganzen Konstruktionsfehler, die wir hier vermuten, auch gemacht worden sind. Wer Namen wie HWnd benutzt um ein "Beispiel" zu posten, der benutzt sie in den meisten Fällen in ähnlicher Form auch im "richtigen Programm". Alles was wir hier schreiben ist fachliche Kritik, weil wir davon ausgehen, dass Du noch nicht weißt und Du bereit bist, zu lernen.
Speedy77
User
Beiträge: 18
Registriert: Samstag 13. März 2021, 13:14

Hallo Sirius3,

Mein Hauptfenster heißt Hauptfenster_Regler_GUI und meine Klasse für die Variablen Variablen_Reglerkommunikation ...
Nur beim Import nenne ich diese dan um in zB. VarKom --> Der Name hätte aber auch Widerspruch ausgelöst...

So habe ich, ich muss leider zugeben, nur die meisten Objekte (90%) benannt... Mein Rechnersystem Ist als Srtartsystem ein Lubuntu, hier starte ich je nach Bedarf DOS oder Windows XP bis Win10, von hier gehts weiter mit einem Remotedesktop auf eine Raspberry PI im Netzwerk über W-Lan, worauf ich Programmiere. Ist also ein bisschen träge :shock: :lol: und damit über Copy&Paste alles rüber zu kopieren ist lässtig. Aus diesem Grund Versuche ich die Variablen im Code so zu bennenen damit der Sinn in aller Kürze erkennbar ist, der Code übersichtlich bleibt und nur der Sinn dargestellt wird. Wie gesagt... Ich gebe Euch Recht was die Benennung und Konventions angeht.

Das mit den Queues schau ich mir gleich an...
...Und auch das Beenden eines Threads geht nur kooperativ, also in dem das Hauptprogramm dem Thread ein Signal sendet "bitte beende Dich".
Zu dem Punkt ist es ja oft so, das man Threads einsetzt um Aufgaben die länger dauern, z.B. Ping-Abfrage gesamtes Netzwerk, paralell laufen zu lassen. Hier ist aber jeder einzelne Thread nach dem Durchlauf seiner Abfrage zu Ende.

Mein Aufbau ist aber:

Klasse mit Funktionen --> Hauptfunktion mit While-Loop
Thread-Klasse.Hauptfunktion anlegen --> Thread.start()

ab dem Punkt läuft der Thread in Dauerschleife ... ich brauche also auf den Thread nicht zu warten, da dieses Warten bis zum Beenden des Hauptprogrammes dauert

Zum letzten Punkt werde ich dann mal das Forum durchforsten...

übrigens aus dem Grund, dass bei Fragestellungen über alles außer über die Problemstellung diskudiert wird, macht es keinen Spaß das Forum durchzuschauen. Wie gesagt, meine Fehler und eure Hinweise sind zu 100% gerechtfertigt und jeder sollte diese beim Fortsetzen seines Projektes berücksichtigen. Aber sie stehen halt nicht vordergründig zur Diskusion.



Erst einmal vielen Dank für die Unterstützung
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Speedy77: Ja klar hätte die Umbenennung in `VarKom` widerspruch ausgelöst. Warum machst Du das, sinnvolle Namen in unsinnigere Abkürzungen umzubennenen?

Bei den Namen gibt es, wie Sirius3 ja schon anmerkte, Warnsignale. Zum Beispiel das `Variablen_*` im Klassennamen, oder das Du von Klassen mit Funktionen sprichst, riecht halt sehr danach, dass das nicht objektorientiert und sauber gelöst ist, sondern das einfach Funktionen, die auf globalen Variablen operieren in Klassen verschoben wurden. Also etwas was man ohne Klassen schon nicht machen würde, noch ein bisschen komplexer gemacht.

Das `_stop_()` irritiert auch. Das ist jetzt aber nicht `Thread._stop()`‽ Das ist keine öffentliche Methode, und bei *der* sollte man wirklich *ganz dringend* die Finger davon lassen.

Die Rechnerkonstellation ist auch kein sinnvoller Grund keinen tatsächlichen Code zu zeigen. A) Kann ich mir nicht vorstellen, dass das wirklich so träge ist, das Text kopieren ein Problem ist, und B) sollte Text kopieren ein Problem sein, dann ist das so ja überhaupt gar nicht zum Programmieren geeignet.

Du willst also keine Kritik zum Code, willst aber wissen wie man etwas bestimmtes in komplexen, nebenläufigen Programmen löst. Und das sollen wir dann aber ohne den Aufbau zu kennen, beantworten können. Das ist schwierig, um es mal vorsichtig auszudrücken. 🙂

Was die berechtigte Kritik angeht: Wenn Du das weisst, warum handelst Du dann nicht entsprechend? Wenn wir hier Beispiele mit schlechten Namen unkommentiert stehen lassen, denken andere Leser das wäre okay so. Gerade wenn Du Dir für ein Beispiel Namen ausdenkst, verstehe ich nicht wie man auf so etwas kryptisches wie `HWnd` statt einfach `Window` kommen kann‽
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Speedy77
User
Beiträge: 18
Registriert: Samstag 13. März 2021, 13:14

Hallo __blackjack__

Gut... ich bin ja hier um mich weiter zu entwickeln und zu lernen:

Meine Ansatz eine Klasse zu bauen die meine übergeordneten Variablen enthält habe ich mittlerweile Verworfen und bin auf den Queue-Weg abgebogen :P
und ja... Copy und Paste würde schon funktionieren nur die Datein im Unterverzeichnis auf dem Pi 3 zu öffnen (Siehe Anfang --> 70 Dateien) hinzuscrollen... naja.... Asche auf mein Haupt
Der Pi ist ja an alle System angeschlossen und die GUI und das eingentlich Programm laufen ja.
Zu den Namen ist es immer so eine Sache mit dem Einfallsreichtum des Idioten der programmiert (in diesem Fall ich). Ich bin versuch meine Namensgebung im deutschsprachigen Bereich zu lassen was oft an Grenzen stößt... sei es bei einfachen Sachen wie get_ und set_ oder auch dem Umstand der Umlaute, ebenso das kombinieren wie get_Wochentag --> eher lese_Wochentag oder get_weekday... :oops:
Da ich mir ehrlich gesagt alles selbst beibringe und anhand der Anzahl meiner Beiträge auch klar sein sollte, dass ich sehr lange mit Google und Co arbeite ehe ich mich ans Forum wende, kann es schon passieren, dass die aktuellen Code-Schnippsel nicht so sauber sind wie sie sollten. 2. Mal Asche auf meine Haupt --> habe mir auch die Konventionen noch nicht so detailiert angeschaut. Ich schäme mich ja selbst.

Deshalb auch der Fehler mit _stop_() --> ich gehe davon aus der Name "thread_stop" für die Funktion wäre angebrachter

Zum Punkt mit der Kritik zum Code... Doch will ich und ich finde es auch ungeheuer wichtig diese Kritik zu geben. Noch wichtiger ist nur, diese auch anzunehmen und das tu ich. Nur sollte dies getan werden und dann sollte man sich hauptsächlich der Problemlösung zuwenden und nicht in den folgenden 20 Antworten hin und her und immer wieder darauf eingehen.

Das HWnd ist meine (vielleicht blöde) Angewohnheit aus vba... Sorry

Falls es fragen zum Aufbau gibt um das Problem zu lösen, wäre es für mich hilfreich die Frage danach zu stellen. Aber ich kann die mittlerweile knapp 1200 Zeilen aus 25 relevanten Dateien nicht alle posten...
Das schaut sich doch keiner an... Oder? außerdem müsste ich da bei der einen oder anderen erst wieder die Form anpassen (schäme mich zum 2.Mal). Da hier auch sachen dabei sind die ich, so muss ich zu meiner Schande gestehen, einfach nur kopiert habe ohne diese abzuändern.

Ich werde jedenfalls die Sache mit den Queues weiterverfolgen --> könnte ein Stück dauern --> und dann eine Rückinformation zum Gelingen geben.

Danke euch im Vorraus
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Eine vernuenftige IDE sollte eigentlich die Arbeit auf dem Remote Pi via SSH erlauben. Oder du gibst das Arbeitsverzeichnis via Samba frei, und arbeitest auf dem Code ueber das network share. Damit entfallen alle die Probleme mit "es ist so traege" etc pp.
Speedy77
User
Beiträge: 18
Registriert: Samstag 13. März 2021, 13:14

hallo __deets__,

gebe ich Dir recht... Welche IDE auf dem PI könntest Du den empfehlen?
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Speedy77: Eben gerade keine IDE auf dem Pi, sondern eine die lokal auf dem lokalen Rechner läuft. Es gibt welche die direkt unterstützen, das das Programm auf einem per SSH erreichbaren Rechner läuft. Und ansonsten kann man aber auch die Dateien auf dem Pi lokal über eine Freigabe (Samba, NFS, sshfs, …) verfügbar machen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Speedy77
User
Beiträge: 18
Registriert: Samstag 13. März 2021, 13:14

Sorry ... ja klar ... so wie PyCharm z.Bsp. das könnte ich mal in Angriff nehmen ... PuTTY hab ich je eh schon ... per SSH gehe ich aber nur auf die Konsole
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

SSH ist hier nur der unterliegende Transportmechanismus. Das ist orthogonal mit der Konsole. In meinem Emacs-Editor kann ich zB Dateien mit /ssh:user@machine:pfad oeffnen, und bearbeiten, als ob sie lokal vorliegen. In einer parallen Konsole lasse ich dann laufen.
Speedy77
User
Beiträge: 18
Registriert: Samstag 13. März 2021, 13:14

Kurzes Update zur Programmierumgebung:

habe mich jetzt für mich zur besseren Bearbeitung für folgenden Aufbau entschieden (und auch schon umgesetzt):
  • Remote-Desktop als Testeben direkt auf dem Raspberry
  • In meiner Windows10 - VM habe ich Visual Studio Community installiert
  • über samba habe ich mir ein Netzwerklaufwerk zu meinem Projekt (Programmordner auf dem Pi) eingerichtet --> Danke für den Hinweis __deets__

Ergebnis: wesentlich besseres Arbeiten :lol: --> :cry: nur erkennt Visual Studio die Dateistruktur nicht, sodass ich nicht auf die Autovervollständigung zurückgreifen kann. :roll:

Kurz noch zum Programm:

Habe soweit alles ans laufen bekommen --> Threads --> Queues --> ... alles Funktioniert, startet und produziert keine Fehler :D
Habe aber jetzt schon die nächste Anpassung vor... multiprocessing... werde mal die Sachen soweit einbauen und melde mich dann wieder --> Dann auch mit konkreteren Ergebnissen


Falls einer von euch einen guten Hinweis hat wie ich die Autovervollständigung hinbekomme oder woran es liegen könnte, dass es nicht funktioniert... Ich bin für alles offen.
Antworten