Prioritäten bei Threads

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.
Benutzeravatar
Muntliger
User
Beiträge: 40
Registriert: Montag 19. November 2018, 09:09

Solche Funktionen habe ich für jeden Kanal.

Code: Alles auswählen

def channel3_active():
	global ch3_active_hm
	if data.channel3_active and ch3_active_hm:
		ch3_active_hm = False
		conf_logger.info('channel 3 - ACTIVATE')
		print('channel 3 - ACTIVATE')
	else:
		pass

	if not data.channel3_active and not ch3_active_hm:
		ch3_active_hm = True
		conf_logger.info('channel 3 - DEACTIVATE')
		print('channel 3 - DEACTIVATE')
	else:
		pass
Gibt es eine bessere Lösung für einen "Hilfsmerker"?
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Das «else: pass» ist unsinnig. Globale Variablen nicht verwenden. Eine Funktion für alle Kanäle mit einem Parameter für die Kanalnummer wäre besser. `data` kommt aus dem nichts und sollte wohl auch ein Parameter sein, wahrscheinlich eine Liste mit einem Eintrag pro Kanal, am besten Instanzen einer Kanal-Klasse.

Aber ohne den gesamten Code zu kennen, kann man da halt schlecht helfen.
__deets__
User
Beiträge: 14527
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ist das der Code der zuverlässig schnell laufen soll? Wenn ja - wieso sind da print und log statements drin?
Benutzeravatar
Muntliger
User
Beiträge: 40
Registriert: Montag 19. November 2018, 09:09

Das ist im "langsamen" Teil.
Hab's nun so gemacht:

Code: Alles auswählen

def channel6_active():
	global ch6_active_hm
	if data.channel6_active and ch6_active_hm:
		ch6_active_hm = False
		conf_logger.info('channel 6 - ACTIVATE')

	if not data.channel6_active and not ch6_active_hm:
		ch6_active_hm = True
		conf_logger.info('channel 6 - DEACTIVATE')
Benutzeravatar
Muntliger
User
Beiträge: 40
Registriert: Montag 19. November 2018, 09:09

Hab den Code mal Online gestellt - bin für jeden Tipp dankbar.
Jetzt schonmal vielen Dank - ihr habt mir schon sehr weiter geholfen.
So macht das Python - lernen Spaß :)

http://gofile.me/3n8Ri/tTCe22Xs4
__deets__
User
Beiträge: 14527
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dieser Link funktioniert nicht (ggf wegen ad blocker). Was hindert dich daran den Code hier rein zu kopieren?
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Muntliger: Ich komme auch nicht an den Code. Da steht nur endlos lange etwas von „connecting“ und animierte Punkte und nix passiert.

Iiiih, ``global``. Und die Sachen die da in den Bedingungen verwendet werden sollten als Argumente übergeben werden. Also `data` und `ch6_active_hm`. Letzteres müsste dann auch der Rückgabewert der Funktion sein.

Das zweite ``if`` kann ja nicht wahr sein wenn das erste schon wahr war, also eher ``elif`` statt ``if``. Die Bedingung davon kann man auch leicht vereinfachen zu ``elif not (data.channel6_active or ch6_active_hm):``
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14527
Registriert: Mittwoch 14. Oktober 2015, 14:29

ui. Das ist ziemlich wild. Ich habe dir hier wiederholt erklärt, dass die I2C-Kommunikation so wenig wie möglich tun muss. Und du startest stattdessen eine Feiertagsparade in Form eines neuen Prozesses, und wunderst dich, dass Stau ist.

In meinen Augen ist da Hopfen und Malz verloren. Das ist zu viel zu verquer, und muss von vorne begonnen werden.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Bei mir hat das mit dem Download jetzt auch geklappt. Nur mal kurz drübergeschaut und gegruselt. Ich dachte ja bisher immer `data` wäre ein Exemplar von einem Datentyp – das ist ein Modul in dem globale Variablen abgelegt sind auf die alle möglichen anderen Module zugreifen. Das ist ja noch mal eine Stufe schlimmer als das ``global`` in den ”Funktionen”.

Ich habe jetzt nicht alles durchgesehen, aber in jedem Modul das ich gesehen habe sind globale Variablen, ein Haufen ``def``\s aber *keine* Argumente und kein ``return`` in Sicht. Es gibt vielleicht im ganzen Code keine einzige Funktion die den Namen auch verdient hätte. Obwohl doch es gibt wohl zwei. Die dann in allen sechs `channel*`-Modulen als Kopie vorliegen.

Denn für jeden der 6 Kanäle gibt es ein eigenes Modul mit etwas unter 5 Kilobyte die aber bis auf die Kanalnummer anscheinend den identischen Code enthalten. Argh! Ich kann ja noch verstehen das Anfänger auf die Idee kommen einzelne Funktionen oder Codeblöcke zu kopieren, aber durchnummerierte Module mit nahezu gleichem Code sehe ich gerade zum allerersten mal.

Was ich auch zu ersten mal sehe ist das jemand in Python ``<>`` statt ``!=`` verwendet. Das war seit dem ich mit Python angefangen habe schon veraltet. Kein Tutorial oder Buch das ich kenne hat das jemals als Option angeboten. Ich kenne das nur weil es der Vollständigkeit halber in der Liste der Vergleichsoperatoren in der Python-Referenzdokumentation steht. Also bei Python 2. In Python 3 gibt's diesen Operator nicht mehr, da geht nur noch ``!=``.

Jetzt wo ich weiss das es Python 2 ist: Geh den ganzen Code nach Vergleichen mit ``is`` durch und ersetze die durch ``==`` denn Du willst so ziemlich garantiert in keinem der Fälle auf Objektidentität testen sondern auf Gleichheit. Wobei auch das nicht wenn einer der beiden Operanden ein literales `True` oder `False` ist. Das hatten wir ja schon: das fällt entweder weg weil es total unnötig ist, oder man setzt ein ``not`` vor den nicht-literalen Wert. Wobei in dem Code auch viel zu viel Gebrauch von `bool()` gemacht wird. Und von `str()` auch. Beispielsweise bei ``str(float_to_str(act_value))`` ist entweder der `str()`-Aufruf unsinnig oder `float_to_str()` hat einen sehr falschen weil sehr irreführenden Namen. Falls das `act_` in `act_value` „actual“ heissen soll, möchtest Du wahrscheinlich mal in einem Wörterbuch die Bedeutung von „actual“ und „current“ nachschlagen. Falls das `act_` nicht für „actual“ steht ist es ein gutes Beispiel warum man keine Abkürzungen verwenden sollte. Die werden zu leicht missverstanden.

Neben `os.system()` sieht man in ein und dem gleichen Modul auch `os.popen()` und `commands.getoutput()` in wenigen Zeilen Abstand. Normal wäre das man *eine* dieser Varianten versucht und dabei dann in der Dokumentation davon findet das man die nicht mehr verwenden soll, weil die durch das `subprocess`-Modul abgelöst wurden. Der Code sieht aus als hätte da jemand in die Dokumentation vom `subprocess`-Modul geschaut und dann entschieden die dort als veraltet aufgeführten Varianten möglichst *alle* zu verwenden, und ja nur nicht das zu machen was empfohlen wird. Das grenzt ja schon fast an einen Trollversuch. :-D

Den Code kann man komplett in die Tonne hauen. Dann Grundlagen lernen wie Funktionen, und ziemlich wahrscheinlich auch Klassen. Danach dann Anfangen und darauf achten, das auf Modulebene nur Code steht der Konstanten, Funktionen, und Klassen definiert. Kein ``global`` und Funktione und Methoden bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben. Und es gibt ``return`` wenn Werte aus der Funktion/Methode an den Aufrufer zurückgelangen sollen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Vor allem ist der Code so niemals zu warten.
Die Duplizierung aller Funktionen für jeden einzelnen Kanal zieht sich nämlich durch alle Teile. Auch auch durch die config.py.

In der fristboot.py gibt es dann auch noch ein "if True:".

Die Abläufe kann man nicht nachvollziehen. Ich würde das Programm von Grund auf neu schreiben, und zwar ohne auch nur eine einzige Zeile aus dem alten Programm zu kopieren.
Benutzeravatar
Muntliger
User
Beiträge: 40
Registriert: Montag 19. November 2018, 09:09

Ok, ich denke da muss ich mir hilfe suchen - und die Software neu machen/machen lassen.
Danke für eure Geduld
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Die Hilfe steckt natürlich auch hier im Forum.
Hier sind dir ja einige Dinge geraten worden. Wenn du die umsetzt, dann wird es automatisch besserer Code.
Wenn du Fragen hast und lernen willst, dann frag einfach. Wenn du es schaffst, die Hinweise umzusetzen, lernst du dazu und bekommst ein gutes Programm.
Benutzeravatar
Muntliger
User
Beiträge: 40
Registriert: Montag 19. November 2018, 09:09

Eine Grundlegende Frage für mein Verständnis:

Es läuft ein Code - nebenbei sollte ein 2ter laufen welcher eine Blinkende LED mit 3 Farben ansteuert.

Wie wird das am besten gelöst?
2 Threads parallel?
Wie werden die Variablen übergeben, funktioniert das ohne Globale?
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Warum müssen die LEDs denn in einem extra Thread laufen?
Wenn in einem Thread die Infomation anfällt, dass die LED geschalte werden soll, kann dort auch nicht die Schaltung passieren?
Benutzeravatar
Muntliger
User
Beiträge: 40
Registriert: Montag 19. November 2018, 09:09

die LED blinkt immer - wird aber in der Farbe umgeschalten.

Code: Alles auswählen

    onionGpio.OnionGpio(blau).setOutputDirection(0)
    onionGpio.OnionGpio(gruen).setOutputDirection(0)
    onionGpio.OnionGpio(rot).setOutputDirection(0)
    time.sleep(2)

    onionGpio.OnionGpio(blau).setOutputDirection(0)
    onionGpio.OnionGpio(gruen).setOutputDirection(1)
    onionGpio.OnionGpio(rot).setOutputDirection(1)
    time.sleep(0.15)
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dann muss man mit dem Thread kommunizieren, beispielsweise über eine `Queue`.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14527
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ihr müsst euch mal über eure Prioritäten kar werden. Sprichwörtlich und im übertragenen Sinne. Ihr habt einen Riesen Code verhau, der seine Grundfunktion Daten zuverlässig zu erfassen nicht beherrscht, aber die Status LED ist plötzlich wichtig?!?!

Das kann man später immer noch drandekorieren. Und wenn man eine Blink-LED kauft & die an die Stromversorgung des PI hängt.

Aber eure verkorkste Datenaufnahme der Kanäle ohne Aussetzer - die muss laufen.
Benutzeravatar
Muntliger
User
Beiträge: 40
Registriert: Montag 19. November 2018, 09:09

Es geht mir grundlegend drum - wie/wann soll man 2 Threads gleichzeitig laufen lassen?
Ist ja das selbe mit dem Einlesen und weiterverarbeiten.

Einlesen und "Impulslog" - wird so schnell wie möglich ausgeführt.
Verarbeiten und "Wertlog" ist mehr code - wird nur alle 3 Sekunden ausgeführt.
__deets__
User
Beiträge: 14527
Registriert: Mittwoch 14. Oktober 2015, 14:29

Python kann keine Threads gleichzeitig. Die werden immer seriell abgearbeitet, mit diversen Problemen die das verursachen kann. Worauf ja auch schon noisefloor hinwies. Darum kann man die I2C Kommunikation und den Rest nicht im selben Prozess machen - wenn es rund laufen soll. Sondern brauch 2 Prozesse, und die müssen kommunizieren.

Und DAS ist eure große Aufgabe. Ob man dann später nebenbei irgendeinen Blink-Thread dödeln lässt oder da gar ein eigenes Programm für schreibt (was eher Zuviel des guten ist, aber auch geht) - was soll’s. Würde ich gaaaaaaaaaaaanz hinten anstellen.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@Muntliger: man will keine Threads benutzen. Nur manchmal ist man dazu gezwungen. Und wann das der Fall ist, kommt auf den Anwendungsfall an. Grundlegend kann man keine Antwort darauf geben.
Antworten