Ein Objekt über mehrere Prozesse hinweg verwenden

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.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

@deets:
Queue habe ich mir angekuckt und bin dabei halt auf Manager gestoßen und empfinde das als deutlich anfängerfreundlicher in der Bedienung, weshalb ich das dann verwenden wollte. Mit Queue komme ich leider noch nicht klar.
Die Prozesse sind nicht (nur) dazu da etwas schneller zu machen, sondern gleichzeitig. Und von Sirius wurde mir gesagt, dass ich Prozesse und keine Threads verwenden soll, da dies aufs selbe hinauslaufen würde (weil mixen von prozessen und threads nicht sinnvoll ist und ausschließlich threads die berechnungen verlangsamen).
Zum Thema asynchron Programmieren habe ich leider ausschließlich Fragezeichen im Kopf. Also unabhängig jetzt von den technischen Vorraussetzungen, kann ich mir garnichts vorstellen, was asynchron läuft. Ein Beispiel wäre hilfreich, wo sowas sinnvoll ist. Aber auch sonst bezweifle ich, dass sowas in meinem Projekt sinnvoll ist... kann es aber noch nicht richtig beurteilen.

Gerne dürft ihr mir auch per PN helfen. Da kann ich gerne auch mehr davon teilen, was genau ich mache. Das soll nur nicht öffentlich stehen.
Außerdem bin ich auch bereit für kompetente Beratung oder das Basteln von hilfreichen Skriptteilen zu bezahlen. Ich hab immer mal wieder knifflige Fragestellungen und könnte kompetente Hilfe gebrauchen.

Wenn dies allerdings für keinen hier in Frage kommt... dann bleibt mir ja nur solche Fragen hier zu stellen und hoffen, dass jemand helfen kann.
Auf einer freelancer Seite war ich bereits um einzelne Skripte schreiben zu lassen. Aber das klappt nur, wenn ich ein richtiges Projekt übergeben kann, was unabhängig programmiert werden kann. Bei solchen Fragen wie sie sich mir aktuell stellen, ist mehr Austausch von nöten
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist nicht freundlicher. Noch nicht mal für Experten. Wenn wir mal für den Moment außer acht lassen, das du zum aufsetzen diverse Zeilen Code sowie (zumindest was ich gesehen habe) TCP/IP brauchst, mit Portkollisionen usw, ist dich dadurch überhaupt nichts gewonnen. Du hast jetzt eine geteilte Datenstruktur, aber ob und wann sich da was geändert bekommst du gar nicht mit. Dafür brauchst du wieder einen signalisieurungs-Mechanismus. Zb über - Trommelwirbel - eine Queue. Oder ggf. ist er gut genug auch Methoden als Werte zu akzeptieren, so das die als callbacks dienen. Aber wie das dann genau gehen soll ist mir völlig schleierhaft. In welchem mainloop laufen die denn? Und wie arbeitet man dann eigene Aufgaben ab?

Und dann redest du selbst davon, das nicht jeder Client alles wissen sollte. Du diese geteilte Datenstruktur also wieder auf einen oder ggf eine Reihe von Clients beschränken willst. Auch da sind Punkt-zu-Punkt-Queues schon wieder der bessere Ansatz. Ggf auf Server-Seite einfach gruppiert zu einer Gruppe, an die eben alle Nachrichten gemeinsam verschickt werden.

Ein posting welches den Manager erklärt und so manche Probleme damit andeutet: https://stackoverflow.com/questions/254 ... processing

Finde ich gelungen.

Und zu deiner Geheimniskrämerei: so lange du keinen NDA von jemandem unterschreiben lässt, ist Polen offen. Es mag geschmacklos sein, zB eine PN hier hämisch zu veröffentlichen. Verboten ist es aber nicht. Und auch das jemand diese geheimnisvolle Idee nachbaut ist zulässig. Das nur als Hinweis.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und noch ein Nachtrag: der von dir und der Dokumentation beschriebene “kleine Trick” ist ein Teufel in Datenstrukturgestalt. Denn zwischen dem rauspulen des dicts und dem wieder speichern vergeht Zeit, in der ein anderer Prozess ebenfalls damit anfängt. Und vielleicht vor dir fertig wird, oder nach dir. Aber einer von beiden überschreibt damit die Arbeit des anderen. Und schon hast du eine race-condition, mit welcher du dir ganz gemeine Fehler einfängst.

Es hat wirklich gute Gründe, warum Nebenläufigkeit schwer ist, und Message-Passing ein Ausweg aus vielen Problemen darstellt. Was wiederum ein anderes Wort für Queue ist...

Asynchrone Programmierung ist das denken in Ereignissen. Dabei ist der Begriff Ereignis recht weit definiert. Aber Code reagiert auf Ereignisse (“frag diese URL ab”, “timer ist ausgelaufen, tu was”) du erzeugt sie (“stopf Daten in diesen Stream”, “registriere einen Timer”). Das ist zuzugebendermassen nicht trivial, aber mit async await deutlich eleganter geworden. Und das du gerade in einem Traum der Leichtigkeit lebst ist ja auch eher nicht so.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Ja richtig, natürlich wird dann eine NDA unterschrieben.
Dafür bekommt man bei mir dann aber regelmäßig gut bezahlte Aufträge :)
Solange dies aber nicht der Fall ist:

Kannst du mir den aufbau mit den Queues erläutern?
Eine queue kann man sich ja als Liste vorstellen, aus dem man dann nach FiFo die einträge reinpacken bzw rausnehmen kann.
Ich starte zu beginn nun also zig multiprocessing queues und übergebe alle an den Haupt-Prozess und zb jeweils eine queue an jeden anderen Prozess, damit alle Prozesse dadurch mit dem Haupt-prozess in Verbindung stehen.

Nun kann der Hauptprozess was in die queue reintun/rausnehmen und auch der verbundene Prozess kann dasselbe tun, richtig?
Nun sollen Informationen vom Hauptprozess an den , nennen wir ihn Nebenprozess, gehen.
Der Norm Aufbau würde vermutlich so aussehen, dass jede neue Info die der Hauptprozess bekommt in die queue gepackt wird und der Nebenprozess zb in einem extra thread, jede einzelne information nacheinander auspackt und verwertet.

Programmiertechnisch sollte ich das hinbekommen. Aber wir hätten weiterhin diese "Unschönheit", dass nonstop Daten übertragen werden, obwohl der Nebenprozess vllt gerade garkeine Daten braucht, er braucht nur die neusten Infos (zum Zeitpunkt seines aktiv-werdens, was alle 5 sekunden ist), alle Infos davor sind bereits veraltet. (Stichwort "Daten auf Anfrage übergeben und nicht dauerhaft"). Außerdem muss der Hauptprozess, nachdem er eine neue Info bekommen hat und zb 10 Nebenprozesse diese info brauchen, die Info in 10 verschiedene queues packen, anstatt sie nur einmal iwo reinzupacken.
Dein Satz "Ggf auf Server-Seite einfach gruppiert zu einer Gruppe, an die eben alle Nachrichten gemeinsam verschickt werden. " klingt wie eine Lösung für letzteres? Wie gruppiert man?
Muss die "Unschönheit" dass dauerhaft unnötig viele Daten übertragen werden (obowhl nur alle 5 sekunden die aktuellsten gebraucht werden) beseitigt werden? Oder ist das kein Problem und sollte man so machen?

edit:
Zu deinem Nachtrag:
wie über dem manager trick beschrieben, verwende ich Lock während des Zugriffs auf das dict :)
Aber es wäre natürlich schön, eine bessere Lösung zu haben, deswegen widmen wir uns jetzt den Queues.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du behummst dich selbst wenn du denkst, dass der Hauptprozess der ein Datum an 10 Unterprozesse verteilen will dazu nicht auch beim Manager 10 Nachrichten verschickt. Das passiert dann halt unter der Haube. Ob das ein Problem ist wage ich aber so oder so zu bezweifeln.

Und was die Aktualität der Daten angeht gibts es nur zwei Lösungen: entweder immmer alles verteilen (macht dein dict auch so), oder die Unterprozesse fordern explizit den neuesten Satz Daten an. Was davon effizienter ist kann man nicht sagen ohne es ausprobiert zu haben. Freies Rumvermuten hilft da nicht.

Ich würde erstmal alles verteilen, die Clients können sich dann nur diel letzten Daten merken. Das ist einfacher programmiert.

Die Gruppierung heißt einfach nur eine Hilfsklasse zu schreiben, welche eine eine Reihe von Queues hat, und eine Nachricht auf die alle verteilt. Oder noch simpler ein dict(topic -> list(queue)).

Ein lock zur Absicherung hilft gegen die races. Synchronisiert dich aber auch, womit du im Zweifel die Performance in den Keller ziehst.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

soooo... ich hab mal probiert etwas mit queues zu schreiben.

Testclass.test() wird gleichzeitig mit 2 Prozessen aufgerufen. a ist die Prozessnummer. 0 ist der Hauptprozess und 1 ist der Nebenprozess.
Der Hauptprozess packt informationen in die queue und der nebenprozess soll diese erhalten.

Code: Alles auswählen

class Testclass:
    def __init__(self,q,a):
        self.q = q # ein dict mit vielen queues. bei a==0 ist es {1:queue1,2:queue2,...} , bei allen anderen ist es direkt die dazugeörige queue
        self.a = a # instanznummer (zb 0 Hauptprozess , 1 nebenprozess)
        if self.a!=0:
            self.queuespeicher = {} # alle neuen infos werden von der queue erstmal hierdrin gespeichert
            self.queuespeicher["dies"] = 0
            
    def test(self,dummy=None,dummy2=None):
        
        if self.a == 0: # HauptProzess
            time.sleep(0.5) # kurz warten bis andre instanzen ihre threads gestartet haben
            
            i = 0
            while i<1000:
                i += 1
                self.q[1].put({"typ":"dies","response":i})

        if self.a == 1: # erste instanz
            _thread.start_new_thread(self.checkqueue, ()) # ein thread der dauerhaft nebenbei läuft und guckt obs neue infos in der queue gibt
            
            time.sleep(0.55)
            print(self.queuespeicher)
            time.sleep(0.01)
            print(self.queuespeicher)
            time.sleep(0.3)
            print(self.queuespeicher)
            time.sleep(2.3)  ## dies hier darf erst nach dem hauptprozess fertig sein, sonst beendet sich skript nicht.. ?!

        if self.a!=0:
            self.stopcheckqueue() # thread beenden, welcher die queue leert
            self.q.close() # die queue selbst beenden

    def stopcheckqueue(self):
        self.q.put(None) # kill
    
    def checkqueue(self):
        while True:
            ding = self.q.get()
            if ding is None: # stop
                return
            else:
                self.verwerteNeueInfo(ding)
            
    def verwerteNeueInfo(self,dic): 
        self.queuespeicher[dic["typ"]] = dic["response"]
Am besten diskutieren wir erstmal über diesen Code, was man daran anders/besser machen sollte.
Erstaunlicherweise bekomme ich (bisher nur windows getestet) nämlich eine Fehlermeldung, wenn ich es über concurrent.futures.ProcessPoolExecutor(2) aufrufe. RuntimeError: Queue objects should only be shared between processes through inheritance
Keinen Fehler bekomme ich bei meiner üblichen "parallel()" Funktion mit Prozessen.
Um diesen Post übersichtlich zu behalten lasse ich den Code dafür erstmal weg. Kann aber gerne nachgereicht werden.

Mit meiner funktionierenden parallel() Aufrufweise, habe ich aber noch das Problem, dass irgendwas verhindert, dass die Funktion/Klasse returned. Soweit ich weiß erstellt die queue einen thread zum übertragen und blockt daher. Deshalb hab ich self.q.close() für die Nebeninstanz eingebaut. Sofern der Nebenprozess nach dem Hauptprozess beendet wird, wird auch korrekt returned (ohne close tut es das nicht). Aber wenn der Nebenprozess vorher beendet wird, dann blockiert irgendwas weiterhin. Hab deswegen self.q[1].close() im hauptprozess dazugeschrieben, aber das bewirkt nichts.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Hallo,

ich nochmal. Ein englischsprachiger Freelancer hatte mir ein Konstrukt mit BaseManager aus mutliprocessing gebastelt, aber leider funktioniert das auch nicht, wie von mir erhofft (irgendwelche "pickle" probleme), das liegt sicherlich daran, dass ich noch immer nicht verstanden habe, wie das mit Prozesskommunikation läuft und was man da alles übertragen kann und was nicht. Ich habe allerdings auch wirklich keinen Nerv mehr dazu und will nur, wie es für Python ja eigentlich möglich sein sollte, eine fertige library nutzen, und mich nicht mit den ganzen queues usw rumschlagen.

Gäbe es denn jemanden hier in diesem Forum, der mir gegen Bezahlung etwas finden/basteln würde, welches genau das macht, was ich brauche? Natürlich kann ich im privaten Chat auch sehr viel präziser werden, was die Problemstellung ist.
Antworten