Hallo Python Gemeinde,
also ich habe eine Program erstellt was quasi in einem Thread periodisch auf einen Netzwerk Socket zugreift und dort Daten abfragt.
Jetzt habe ich einmal einen Thread der immer nach so ca. 5 Sekunden Daten vom Socket abfragt.
Gleichzeitig habe ich im Programm an anderen Stellen noch Zugriff auf den Socket ohne Thread.
Manchmal kommt es vor das der Thread scheibar stolpert und keine neuen Daten bekommt.
Nun mir geht es darum wie kann man das besser lösen:
Sollte ich alle Zugriffe auf den Socket via Thread machen ?
Wie ist da eine gute Vorgehensweise?
Danke schon mal
Polling von Daten
- __blackjack__
- User
- Beiträge: 13143
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@isnotnone: Das bestätigt im Grunde nur noch mal dass das eine schlechte Idee ist, denn wenn die nicht irgendwie sauber synchronisiert sind, dann können die sich gegenseitig in die Quere kommen.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
- __blackjack__
- User
- Beiträge: 13143
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@isnotnone: „[J]ede Anfrage in einem Thread“ ist mehrdeutig. Falls damit gemeint ist jede Anfrage in einem *eigenen* Thread der nur eine Anfrage macht — nein das muss man nicht. Jede Anfrage in *einem* Thread, der nur für die Anfragen zuständig ist, kann man auch machen, das wäre auch nicht unbedingt eine schlechte Idee.
Stichwort ist „nebenläufige Programmierung“ oder „concurrent programming“ und das ist normalerweise Stoff für ein ganzes Semester. Und in der Praxis hängt das auch alles davon ab was man ganz konkret macht und welche Rahmenwerke beteiligt sind. GUI-Rahmenwerke haben beispielsweise fast alle ihre eigenen idiomatischen Lösungen Threads zu integrieren. Falls man kein GUI-Rahmenwerk verwendet, bietet es sich oft an eine eigene Ereignisschleife in seinem Hauptprogramm zu basteln.
Stichwort ist „nebenläufige Programmierung“ oder „concurrent programming“ und das ist normalerweise Stoff für ein ganzes Semester. Und in der Praxis hängt das auch alles davon ab was man ganz konkret macht und welche Rahmenwerke beteiligt sind. GUI-Rahmenwerke haben beispielsweise fast alle ihre eigenen idiomatischen Lösungen Threads zu integrieren. Falls man kein GUI-Rahmenwerk verwendet, bietet es sich oft an eine eigene Ereignisschleife in seinem Hauptprogramm zu basteln.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Ich versuche mal die Klassen zu posten die daran beteiligt sind ...
Traue mich eigentlich immer nicht, aber ich mach das mal trotzdem jetzt, bitte mich nicht in der Luft zerreißen
Der Proxy der auf den MPD zugreift
Der Fetcher
Daten holen indem auf die Klassenvariable zugegriffen wird
song = fetcher.currentsong
dann gibt es aber auch noch Zugriffe auf den MPDProxy ohne Thread
self.client = MPDProxy(server, port)
client.status().get("state")
Zusammenfassend:
Es gibt einen Thread der immerfort Song Daten abfragt, der Zugriff erfolgt über fetcher.currentsong
Es gibt Anfragen an den MPDProxy ohne Thread via client.getSth()
Traue mich eigentlich immer nicht, aber ich mach das mal trotzdem jetzt, bitte mich nicht in der Luft zerreißen
Der Proxy der auf den MPD zugreift
Code: Alles auswählen
class MPDProxy:
def __init__(self, host="mpdhost", port=6600):
self.client = mpd.MPDClient()
self.host = host
self.port = port
# number of (reconnects)
self.reconnects = 0
self.isConnected = False
self.connect(host, port)
# because we do not know what function will be called, we use __getattr__
# eg. mpd.idle() -> __getattr__ self: <mpd_proxy.MPDProxy object at 0x7f5fa7265b70>, name: idle
def __getattr__(self, name):
#if self.isConnected: #debug not shure if neccesary
return self._call_with_reconnect(getattr(self.client, name))
def connect(self, host, port):
what = "connecting" if self.reconnects == 0 else "reconnecting"
logging.info(f"{self.reconnects}:{what} ...")
self.reconnects bananapi+=1
self.client.connect(host, port)
#if self.client.mpd_version:
if self.client:
self.isConnected = True
logging.info(f"MPDPROXY connected to {host}:{port}")
else:
self.isConnected = False
logging.info(f"MPDPROXY not connected!")
def _call_with_reconnect(self, func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except mpd.ConnectionError as e:
self.isConnected = False
self.connect(self.host, self.port, )
logging.error(f"{e}")
return func(*args, **kwargs)
except OSError as e:
self.isConnected = False
logging.error(f"{e}")
self.client.disconnect()
self.client = mpd.MPDClient()
pass
except Exception as e:
logging.error(f"{e}")
pass
return wrapper
Code: Alles auswählen
import time, os
from threading import Thread, Event
# logging
import logging
from util import *
from mpd_proxy import MPDProxy
import tkinter as tk
class Fetcher(Thread):
def __init__(self, playerApp = None):
Thread.__init__(self)
self.stopped = Event()
self.playerApp = playerApp
# to get/set config user self.playerApp handle
self.client = self.playerApp.getClient()
self.currentsong = None
self.config = playerApp.appconfig
self.fetcherIntervall = self.config.get("fetcherIntervall")
def run(self):
# https://stackoverflow.com/questions/12435211/threading-timer-repeat-function-every-n-seconds#12435256
name = self.__class__.__name__
while not self.stopped.wait(int(self.fetcherIntervall)):
logging.debug(f"THREAD is running {self.client}/{self.fetcherIntervall}....")
self.client = self.playerApp.getClient()
if not self.client: logging.error("No Client (None) ")
if self.client:
logging.debug("Fetching Data ...")
self.currentsong = self.client.currentsong()
logging.debug(self.currentsong)
def stop(self):
name = self.__class__.__name__
logging.info(f"{name}: Thread stops ...")
self.stopped.set()
song = fetcher.currentsong
dann gibt es aber auch noch Zugriffe auf den MPDProxy ohne Thread
self.client = MPDProxy(server, port)
client.status().get("state")
Zusammenfassend:
Es gibt einen Thread der immerfort Song Daten abfragt, der Zugriff erfolgt über fetcher.currentsong
Es gibt Anfragen an den MPDProxy ohne Thread via client.getSth()
- __blackjack__
- User
- Beiträge: 13143
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@isnotnone: Was ist denn der Sinn von diesem Thread? Warum nicht einfach den aktuellen Song vom MPD abfragen wenn er gebraucht wird? Falls das ”zu oft” der Fall ist, kann man ja einfach einen Cache basteln der nur nach x Sekunden tatsächlich neu abfragt.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
- __blackjack__
- User
- Beiträge: 13143
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Na halt den Wert zwischenspeichern statt ihn jedes mal neu vom MPD abzufragen. Falls das tatsächlich nötig/sinnvoll ist.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Hab jetzt den Thread auf Eis gelegt .
Nutze so wie es __blackjack__ vorgeschlagen den direkten Aufruf ohne Thread
self.update benutzt zusätzlich noch einen Cache
Damit tritt der Fehler nicht mehr auf
Nutze so wie es __blackjack__ vorgeschlagen den direkten Aufruf ohne Thread
Code: Alles auswählen
self.after(seconds, self.update)
Damit tritt der Fehler nicht mehr auf