Seite 1 von 1

ist hier threading sinnvoll?

Verfasst: Mittwoch 20. Dezember 2017, 10:58
von Robbse1990
Hallo Zusammen,

ich stehe mal wieder vor dem Problem, das ich eine Lösung für ein Problem gefunden habe, jedoch ich mir nicht sicher bin, ob der Ansatz sinnvoll ist. Vielleicht gibt es einen besseren weg?

Szenario:
thread 1: liest alle 15min Sensor (datum, Temperatur und Luftfeuchtigkeit) am Pi aus und schreibt Messdaten in Datei
thread 2: liest alle 60sec den Sensor aus, wenn die Werte kritisch sind, wird ein Plot erstellt und dieser per Mail versendet.
thread 3: erstellt immer am letzten Tag des Monats einen Graphen des Monates und versendet diesen per Mail

Problem:
Wenn ich thread 1 und 2 starte, misst er mir zwar alle 15min, jedoch 3-6 mal im Abstand von paar Sekunden. Wenn thread 1 alleine läuft, geht alles gut. Auch wird die Mail nicht immer bei Alarm gesendet, mal ja, mal nicht. Ich glaube ich habe hier einen gravierenden Fehler im Kopf.

Code: Alles auswählen

import threading
import time
from send_mail import *
from funktionen import *



#Definition der Feuchte:
max_feuchte = 65.0
test_intervall = 60 
schreib_intervall = 900
datei_pfad = 'Messdaten.txt'

#####################################################################################
#daten lesen und in datei schreiben 

class schreiben(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:
            #Sensor und Zeit auslesen
            zeit     = time.strftime("%a:%d.%m.%Y %H:%M:%S")
            var_temp, var_hum = sensor_read()
            #in datei schreiben     
            with open (datei_pfad, "a") as fh:
                fh.write('{}\t{}\t{}\n'.format(zeit, var_temp, var_hum))          
            time.sleep(schreib_intervall)

#####################################################################################
#alarm

class alarm(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:	
		#Sensor und Zeit auslesen
        	zeit     = time.strftime("%a:%d.%m.%Y %H:%M:%S")
        	var_temp, var_hum = sensor_read() 
 
        	if (var_temp < 10.0 or var_temp > 35.0 or var_hum > max_feuchte):

			#in datei schreiben     
        		with open (datei_pfad, "a") as fh:
                		fh.write('{}\t{}\t{}\n'.format(zeit, var_temp, var_hum))
	    		pfad_mail_anhang = plot_alarm(datei_pfad,5,max_feuchte)
            		send_mail_warnung(var_temp,var_hum,zeit,pfad_mail_anhang)
 			time.sleep(43200)#12h

		time.sleep(test_intervall) 
       

t1 = schreiben()
t2 = alarm()
t1.start()
t2.start()


Re: ist hier threading sinnvoll?

Verfasst: Mittwoch 20. Dezember 2017, 11:30
von narpfel
Moin,

ich würde das Problem eher mit einer (bzw. mehreren) systemd-Timer-Unit (`man systemd.timer`) lösen, die das Programm im jeweiligen Intervall startet.

Eventuell programmierst du auch gerade etwas wie Munin nach.

Zum gezeigten Code: Ist das wirklich der Code, den du laufen lässt? In Zeile 48 ist die Einrückung kaputt und eigentlich sollte der Code deswegen nicht laufen. Benutzt du Python 2 oder 3?

Die Klassennamen entsprechen nicht PEP 8. Klassennamen sollten in `CamelCase` geschrieben werden und Objektnamen darstellen. „Schreiben“ ist kein sinnvoller Name für ein Ding.

Eine `__init__`-Methode, in der nur die `__init__`-Methode der Elternklasse aufgerufen wird, kann ersatzlos gestrichen werden, weil das per default passiert.

Wann wird Zeile 51 ausgeführt? Und wie lange dauert ein Durchlauf der Endlosschleife in Zeile 37?

Für CSV-Dateien sollte das `csv`-Modul benutzt werden, anstatt das selber nachzuprogrammieren. Alternativ `numpy` oder `pandas`, wobei das overkill wäre, nur um eine Zeile zu schreiben.

Re: ist hier threading sinnvoll?

Verfasst: Mittwoch 20. Dezember 2017, 11:31
von Sirius3
@Robbse1990: für mich stellt sich die Frage, warum Threads. Das sind drei unabhängige Programme.

Re: ist hier threading sinnvoll?

Verfasst: Mittwoch 20. Dezember 2017, 11:41
von sebastian0202
Hallo,



dein 'time.sleep(test_intervall)' aus der Klasse Alarm steht außerhalb der while - Schleife, ist das beabsichtigt?
Dadurch wird die Schleife eben alle 12h ausgeführt und nicht 60 Sekunden.
In deinem Beispielcode sind einige Einrückungen falsch.

Du schreibst übrigens zwei mal in deine Datei. Einmal mit der Klasse Alarm und einmal mit der Klasse Schreiben.

Re: ist hier threading sinnvoll?

Verfasst: Mittwoch 20. Dezember 2017, 12:44
von Robbse1990
hier ist was mit dem code schiefgegangen bzw. mit dem einrücken. Ich habe das einfach mit copy and paste aus dem Programm übernommen, kann es sein das es einrückfehler gibt, die man nicht sieht? Dachte es ist egal ob tab oder leerzeichen, hauotsache konsistent innerhalb einer funktion:

Code: Alles auswählen

import threading
import time
from send_mail import *
from funktionen import *



#Definition der Feuchte:
max_feuchte = 65.0
test_intervall = 60 #in Sekunden (einmal die Stunde sind 3600sec) 
schreib_intervall = 900
datei_pfad = 'Messdaten_neu.txt'



#####################################################################################
#daten lesen und in datei schreiben 

class schreiben(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:
            #Sensor und Zeit auslesen
            zeit     = time.strftime("%a:%d.%m.%Y %H:%M:%S")
            var_temp, var_hum = sensor_read()
            #in datei schreiben     
            with open (datei_pfad, "a") as fh:
                fh.write('{}\t{}\t{}\n'.format(zeit, var_temp, var_hum))          
            time.sleep(schreib_intervall)

#####################################################################################
#alarm

class alarm(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:	
		#Sensor und Zeit auslesen
        	zeit     = time.strftime("%a:%d.%m.%Y %H:%M:%S")
        	var_temp, var_hum = sensor_read() 
 
        	if (var_temp < 10.0 or var_temp > 35.0 or var_hum > max_feuchte):

			#in datei schreiben     
        		with open (datei_pfad, "a") as fh:
                		fh.write('{}\t{}\t{}\n'.format(zeit, var_temp, var_hum)
                pfad_mail_anhang = plot_alarm(datei_pfad,5,max_feuchte)
            	send_mail_warnung(var_temp,var_hum,zeit,pfad_mail_anhang)
                time.sleep(43200)#12h
            time.sleep(test_intervall) 
       

t1 = schreiben()
t2 = alarm()
t1.start()
t2.start()


@narpfel
Ich verwende python 2, die Idee ist, das alle 60 Sec (=testintervall) geschaut wird, ob die Werte im grünen Bereich liegen. Falls nciht, bekomme ich die Mail mit dem Graphen. Damit ich nicht alle 60 Sekunden eine Mail bekomme, soll das Programm in so einem Fall für 12 Stunden ruhen. Das gibt mir genung Zeit alles zu checken...

@sirius
ziel ist es später noch eine art forcemodus einzubinden. Wenn die Werte gewisse Zeit in einem "orangenen" Bereich liegen, soll der Testintervall angepasst und der lüfter dazugeschaltet werden. Geht vllt auch ohne threading, aber das erschien mir eleganter als 2 oder 3 Programme. Wenn das aber quatsch ist, lass ich das.

@sebastian
das war ein copy paste fehler, oben der richtige code. Es ist beabsichtigt, das im falle eines alarmes zusätzlich in die datei geschrieben wird.

@all
Danke! Freu mich über jede Kritik, Hilfe, Antwort

Re: ist hier threading sinnvoll?

Verfasst: Mittwoch 20. Dezember 2017, 12:47
von __deets__
Egal ob mit drei Programmen oder Units oder Threads: man muss denke ich sicherstellen, das konkurrierende Zugriffe auf den sensor ok sind. Also entweder testen, oder nachlesen, oder prophylaktisch durch ein gemeinsames lock verhindern. Letzteres ist natürlich in einer multi-thread Umgebung am einfachsten.

Re: ist hier threading sinnvoll?

Verfasst: Mittwoch 20. Dezember 2017, 13:02
von __deets__
Mit der neuen Beschreibung kann man nun sagen: dein Ansatz ist falsch. Eine solche Logik läuft ja auf verschiedene Programmzustände hinaus, durch die verschiedene Aktionen getriggert werden. Ein solches Zusammenspiel ergibt sich nicht aus dem parallelen starten von Programmteilen. Im Gegenteil.

Du musst präzise definieren, welche Zustände es gibt, und wie das Programm von einem in den anderen gelangt. Eine in der Informatik dafür gerne genommene Struktur ist die des endlichen Automaten. Damit kannst du ein solches Verhalten modellieren, und auch recht gut in ein Programm umwandeln.

Re: ist hier threading sinnvoll?

Verfasst: Mittwoch 20. Dezember 2017, 14:52
von Sirius3
@Robbse1990: das Mischen von Tabs und Leerzeichen solltest Du nicht machen, auch wenn es vielleicht geht. Aber je nach Editor geht die Eintrückung dann doch kaputt. Nimm immer 4 Leerzeichen pro Ebene. Noch ein Paar Anmerkungen zum Code. Ein Modul das funktionen heißt, ist kein sinnvolles Modul, weil es keinen sinnvollen Namen hat. Module kapseln zusammengehörige Teile, einfach nur Funktionen bilden aber keine Einheit. Sternchenimporte sind generell zu vermeiden, gib die importierten Namen explizit an. Konstanten werden KOMPLETT_GROSS geschrieben, also MAX_FEUCHTE, etc. Für Deine Threads brauchst Du keine Klassen, weil sie keinen Zustand haben. Benutze das target-Argument von Thread. Die beiden gezeigten Threads machen das selbe, so dass es besser wäre nur eine Schleife zu haben und dann sind gar keine Threads mehr nötig. Zeile 44: da sind zwei Zahlen, die Du als Konstanten herausführen solltest; die Klammern sind unnötig.

Re: ist hier threading sinnvoll?

Verfasst: Donnerstag 21. Dezember 2017, 11:28
von Robbse1990
ich habe jetzt 3 seperate Programme geschrieben.

1. Liest den Sensor zu bestimmten Zeiten aus
2. Schickt je am Monatsende einen Graphen des kompletten Monats per Mail raus
3. testet alle 60 sec die Werte und schickt Mail, falls was im roten Bereich ist

Habe eure Tipps umgesetzt, macht Sinn. Danke!