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

Hallo :)

mit diesem Code starte ich mehrere Prozesse und Threads:
viewtopic.php?p=314946#p314946

Diese so gestarteten "Instanzen" lassen alle nun einen Code laufen ala:
Api Calls machen, Ergebnis auswerten, warten -> repeat
Deswegen mehrere Prozesse und Threads die "dasselbe" machen, weil sie es mit etwas anderen Einstellungen machen.

Ab und zu ist es praktisch, wenn über die gestarteten Threads und Prozesse hinweg, diese Instanzen Informationen miteinander teilen können.
Als Lösung dafür wurde mir "pymemcache" ans Herz gelegt und es funktioniert auch sehr schön, für alle Objekte die sich als string darstellen lassen.

Doch ich verwendet unter anderem auch websocket API für die API Calls.
Da wäre es denke ich am Besten, wenn man nur 1 websocket Verbindung öffnen würde, die dann von allen Isntanzen, egal auf welchem Prozess, genutzt werden könnte.
Doch so ein Objekt mit einer aktiven weboscket verbindung kann ich ja wohl kaum in den cache legen, oder?
Also wie mache ich das nun? Eine globale Verbindung kann ich auch nicht verwenden, oder? siehe viewtopic.php?p=313220#p313220

Oder gibt es keine Möglichkeit und ich sollte einfach pro Prozess eine Verbindung starten (über Threads hinweg geht die Verwendung ja problemlos)?
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: eine offene Verbindung ist etwas anderes, als statische Werte. Während man zweiteres beliebig oft kopieren kann, existiert ersteres nur ein mal. Du brauchst also einen Prozess, der die Websocketinstanz verwaltet und Interprozess-Kommunikation, um diesem Prozess Anfragen zu stellen.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Sirius3 hat geschrieben:@Serpens66: eine offene Verbindung ist etwas anderes, als statische Werte. Während man zweiteres beliebig oft kopieren kann, existiert ersteres nur ein mal. Du brauchst also einen Prozess, der die Websocketinstanz verwaltet und Interprozess-Kommunikation, um diesem Prozess Anfragen zu stellen.
Interprozesskommunikation sind dann Pipes und multiprocessing.queue , richtig? (wobei ich noch nicht verstanden habe, ob pipes und queue 2 unterschiedliche Methoden sind, oder ob die queue mithilfe von pipes funktioniert)

Ich hatte bereits jemanden beauftragt mit interprozesskommunikation zu schreiben. Er hat nur ein klein wenig code mit multiprocessing.queue geschrieben, kam dann aber mit der pymemcache Lösung, welche für die meisten Objekte ja tatsächlich schöner ist. Auch weil man bei einer Queue nur schwer managen kann wer was an infos bekommt und Pipes sollen laut stackoverflow kommentaren ganz ganz furchtbar sein.

Mein Gedanke war bereits eine einzelne Instanz zu erstellen, welche sich um diesen API Kram kümmert. Diese wäre bisher lediglich ein Thread auf einem der 2 Prozesse gewesen.
Die websocket Daten könnte man dann natürlich auch über pymemcache übermitteln, allerdings kam mir das nicht sinnvoll vor, weil die websocket instanz dann ständig, bei jeder websocket message, die daten im cache aktualisieren müsste und da anscheinend gleichzeitg schreiben und lesen im cache nicht funktioniert, wäre das unmöglich bei zig messages pro sekunde.
Daher ist eine "anfrage nach aktuellen gesammelten Infos" schon sinnvoller... aber ob pipes/queues da die Lösung für sind?
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: der Flaschenhals wäre ja die Websocket-Kommunikation, weil die nur seriell eine Anfrage nach der anderen bearbeiten kann. Wie und was da im Speicher hin und herkopiert wird spielt da keine Rolle. Pipes sind Streams, Queues sind Message-basiert. Wie das eine oder andere intern implementiert ist, spielt für Dich keine Rolle.

Es muß eine Queue zwischen jeden Prozessen, die kommunizieren wollen, existieren. Die alle zu verwalten ist natürlich Aufwand. Oder man hat eine zentrale Stelle, bei Dir memcached und nutzt (mißbraucht?) den Cache dazu, oder nutzt gleich das richtige Werkzeug, einen MessageBroker wie RabbitMQ.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Es ist im Grunde relativ simpel:

- Queues/Pipes sind FIFOs. Daten kommen rein, und werden dann auch konsumiert. Was die Konsumenten damit machen ist ihrs. Wenn viele Konsumenten das gleiche sehen sollen, muss jeder eine eigene Nachricht kriegen vom Produzenten.
- PyMemcache ist ein geteilter Datenhaufen. Jeder Konusment sieht jeweils den letzten Stand. Man spart sich also viele Nachrichten, die ggf. gar nicht notwendig waren, weil der Konsument in dem Moment gar nix wissen musste. Sollen jetzt aber viele Produzenten diesen Zustand aendern, wird's schwierig, weil die ihre Aenderungen sonst gegenseitig ueberschreiben.

Und da websockets ebenfalls FIFOs sind, liegt die Vermutung nahe, dass auch die Verbindung von verschiedenen Prozessen die dann ihre Daten an den socket lieferen wollen, dies per FIFO tun.

In diese Fall wohl eher eine Pipe. Der Unterschied ist, dass eine Queue viele Konsumenten hat, von denen der erste die Nachricht abgreift. Eine Pipe ist immer 1:1.

Unter der Haube sind Queues mit diversen Pipes implementiert.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

vielen dank euch beiden :)

Da Sirius es als "richtiges Werkzeug" bezeichnet hat, gehe ich mal davon aus, dass die Beste Wahl RabbitMQ ist? (anstatt dass ich mir nur selbst verwuschtelten Code mit Pipes/queue schreibe).
Google spuckt dazu folgende 2 Anleitungen aus:
https://www.rabbitmq.com/tutorials/tuto ... ython.html
https://www.digitalocean.com/community/ ... -consumers

Bei dem einen ist die Rede von "puka" und beim anderen von "pika". Dachte erst einer hätte nen Schreibfehler drin, aber es scheinen tatsächlich 2 unterschiedliche libraries zu sein. Googlen nach "python pika puka" bringt soweit ich sehen kann nichts hilfreiches hervor, welches von beiden ich nun nehmen sollte...
Welcher der Anleitungen sollte ich folgen ,bzw ist puka oder pika besser?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ach du liebe Guete. *Das* wuerde ich nun nicht verwenden. Das ist ja eine persistente Queue, und eben eine Queue und keine Pipe. Dafuer wuerde ich die ganz normalen multiprocessing-Pipes verwenden.

RabbitMQ ist toll, wir benutzen das auch. Aber ich bezweifele, das das hier die richtige Wahl ist. Wenn dein Websocket-Besitzer stirbt, dann sind ganz bestimmt auch die Daten, die er verschicken soll, so gar nicht mehr gueltig. Dann muss das System eh wieder angeschmissen werden. Da hat man nix von Persistenz solcher Daten.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

ok danke.

Vllt nochmal zu dem Aufbau an den ich jetzt denke:
Ich starte eine eigene Instanz( eigenen Prozess), der für die API calls zuständig ist, die von jeder anderen Instanz gebraucht werden.
Auch soll diese API-Instanz die websocket verbindungen starten (damit wir eben nur eine aktive Verbindung brauchen).
Die weboscket verbindung ist bereits ein eigenständiges Skript welches ein fertiges websocket modul verwendet (ws4py), dh. dies läuft bereits in einem thread oder was auch immer im Hintergrund, empfängt die messages, verarbeitet sie und speichert die relevanten ergebnisse in self. Variablen.
Dh diese API-Instanz braucht sich nicht um die messages oderso kümmern, sondern nur um den start der websocket verbingung und kann dann direkt auf die relevenaten Ergebnisse zugreifen.

So, die Aufgabe ist nun dafür zu sorgen, dass alle anderen Insanzen Zugriff auf die API Ergebnisse der API-Instanz bekommen.
Dafür sollte ich nun also Pipes verwenden? Dh. ich mache eine Pipe von Instanz1 zu API-Instanz und eine weiter Pipe von Instanz2 zur API-Instanz usw? (davon ausgehend dass Instanz1 und Instanz2 nicht kommunizieren brauchen).

Da zum aktuellen Zeitpunkt jede Instanz noch selbst die API Calls macht, werden,wenn zb 10 API calls gemacht werden sollen, von dieser Instanz nochmal 10 Threads gestartet, damit das Warten auf die Antwort insg verkürzt wird.
Wenn ich diesen Aufbau nun beibehalte und für zb 6 der API Calls stattdessen eine Anfrage an die API-Instanz schicke, führt das zu Problemen weil dann 6 Anfragen gleichzeitig über dieselbe Pipe müssen?
Falls ja, sollte ich dann lieber was anderes verwenden? Oder kann man da irgendwie lock implementieren? Oder sollte ich den Urpsrungscode umschreiben, sodass diese 6 Anfragen einfach in Reihe geschaltet sind und dadurch erst weitermachen, wenn der vorherige fertig ist (letzteres wird etwas unschön, ich würde das Verändern des Ursprungscodes gerne vermeiden, bzw so gering wie möglich halten)
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: das ist alles sehr verwirrend. Du sprichst von API-Calls, aber auch davon dass von irgendwoher die Ergebnisse schon in self-Variablen liegen? Wie kann das sein? Websocket ist asynchron und bidirektional. Das heißt, es werden Nachrichten in beide Richtungen verschickt, die erst einmal nichts miteinander zu tun haben. Darauf kann man verschiedene Operationsmodi aufbauen, RPC, Server-Push, etc. Bei RPC müßte man die Anfrage, die von einem Deiner Instanzen kommt, mit der Antwort, die vom Server kommt irgendwie verknüpfen und die Antwort an die Instanz zurück schicken.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Sirius3 hat geschrieben:@Serpens66: das ist alles sehr verwirrend. Du sprichst von API-Calls, aber auch davon dass von irgendwoher die Ergebnisse schon in self-Variablen liegen? Wie kann das sein? Websocket ist asynchron und bidirektional. Das heißt, es werden Nachrichten in beide Richtungen verschickt, die erst einmal nichts miteinander zu tun haben. Darauf kann man verschiedene Operationsmodi aufbauen, RPC, Server-Push, etc. Bei RPC müßte man die Anfrage, die von einem Deiner Instanzen kommt, mit der Antwort, die vom Server kommt irgendwie verknüpfen und die Antwort an die Instanz zurück schicken.
Entschuldige, ich hab versucht so deutlich wie möglich zu sein =/

Also für die weboscket verbindung habe ich ein eigenständiges Websocket-Skript. Dieses importiert "ws4py". Diesem Modul brauch ich nur sagen, "mach ne Verbindung zu da und da auf und folgendes sollst du machen, wenn eine message reinkommt". Dass durch das Warten auf messages nicht geblockt wird, wird alles in ws4py geregelt. Und wenn ne message reinkommt, dann speichere ich zb die aktuellste in self.last_message.
Mein Hauptskript, welches dieses websocket-skript importiert, ruft dann einfach nur noch "start" auf und hat Zugriff auf self.last_message.

Lange Rede kurzer Sinn:
Für den Aufbau mit API-Instanz, Instanz1 und Instanz2 ist websocket völlig irrelevant. Vergesst, dass ich jemals was von websocket geschrieben habe (auch wenn es das Hauptthema ist :D). Also wie gesagt, vergesst websocket.
Ich habe also 3 (oder mehr) Prozesse (instanzen) und diese sollen untereinander ihre self. variablen austauschen können. Das wars schon.

(wobei es evlt doch komplizierter ist, da die API instanz ja das websocket-skript imprtiert hat.. und dies nun ein "objekt" ist..und kann man objekte so einfach übertragen?... aaaaah ich werd hier noch verrückt :D wenn man sich mit sowas n icht auskennt, ist es wirklich schwer zu beschreiben was man möchte, bzw man weiß ja garnicht was überhaupt möglich ist (Pie, queue, rabbit, RPC und und und ... ich dreh durch...)
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Serpens66 hat geschrieben:aaaaah ich werd hier noch verrückt wenn man sich mit sowas n icht auskennt, ist es wirklich schwer zu beschreiben was man möchte
So schwer ist das gar nicht: vergiss erst einmal Python und erkläre in normaler Sprache was Du rein sachlich weißt und welches Ergebnis Du erzielen möchtest. So scheinst Du die API einer Anwendung auf einem entfernt laufenden Server zu kennen. Diese scheinst Du in definierten Abständen aufrufen zu wollen um mit den Rückgabewerten dann weiter irgendetwas anzustellen. Soviel meine ich jedenfalls inzwischen verstanden zu haben. Erst wenn Du die Aufgabe klar beschreiben kannst, ist auch eine Lösung möglich.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: meiner Meinung nach denkst Du noch zu statisch. Nachrichten kommen und gehen und Du kannst nicht den Zeitpunkt bestimmen. Wenn Du dann noch eine Indirektion über einen Websocket-Broker hast, wird das ganze nicht einfacher. Die übliche Lösung ist es, alles komplett asynchron zu programmieren, was wieder ein völliges Umdenken erfordert: man stellt eine Anfrage, wartet dann aber nicht auf das Ergebnis, sondern bekommt nur ein sogenanntes Promise, das man dann, wenn es nötig ist, fragen kann, ob das Ergebnis inzwischen vorliegt.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Ich habe mich für den Anfang nun für:
multiprocessing.Mananger.dict()
entschieden.

Auf die Weise werde ich Informationen zwischen mehreren Processen synchron halten.
Bei jedem Zugriff/Änderung werde ich ein multiprocessing lock verwenden.

Da ich Python 3.4 verwende, ist mir schon aufgefallen, dass man um das manager dict synchron zu verändern, einen kleinen Trick braucht (ab 3.6 wohl nicht mehr).
Schematisches Beispiel:

Code: Alles auswählen

mgr = multiprocessing.Manager()
d = mgr.dict()
d = {"meineDaten":{"liste1":[1,2]}}
# synchron über alle Prozesse den 2ten eintrag der liste auf eine 3 ändern:
_d = d["meineDaten"] # in lokaler variable speichern
_d["liste1"][1] = 3 # änderungen nach belieben vornehmen
d["meineDaten"] = _d # updaten
Nun zu meiner Frage:
Ich würde gerne, dass ich 1 Prozess habe, welcher zb via API alle paar Sekunden Daten abfragt und das Ergebnis in self. Variablen abspeichert (allerdings simultan von mehreren websiten, weshalb dadurch im extremfall alle zb 0.01 sek neue daten eingehen). Anstatt diese Daten nun im 0.01 sekundentakt oder häufiger für alle prozesse zu synchronisieren, würde ich diesen Synchronisationsprozess lieber auf Abruf starten. So nach dem Motto "Prozess 2 braucht nun folgende Daten, schick sie mir mal bitte". Denn dies wird deutlich seltener als alle 0.01 sekunden oderso nötig sein, vllt alle 5 sekunden.

Wie mache ich das am geschicktesten?

Mir ist aufgefallen, dass ich sogar ganze self. Funktionen in so ein synchron gehaltenes dictionary packen kann.
Ich dachte so könnte ich das "auf Abruf" realisieren.Allerdings hab ich auch schon gemerkt, dass diese Funktionen, wenn ich sie im anderen Prozess dann aufrufe, mit den self. Werten arbeiten, die gültig waren, als die Funktion in das dictionary gepackt wurde. Letzlich würde das also nur heißen, anstatt alle 0.01 sek ein bestimmtes dictionary zu synchroniseren, müsste ich alle 0.01 sekunden die Funktion synchronisieren, was vermutlich bedeutet, dass gleichzeitig ALLE self. Variablen mit abgespeichert werden? Demnach ist das wohl nicht zu empfehlen, wenn ich nur bestimmte und nicht alle self. Werte brauche, oder?

Ein anderer Weg wäre die relevanten Daten nur zu synchronisieren, wenn quasi eine Aufforderung vom anderen Prozess in Form eines zusätzlichen manager dicts eingeht. Das manager dict enthält dann nur sowas wie "braucheDaten":True und wird alle 0.01 sekunden gecheckt. Wenn der Wert True ist, werden die Daten synchronisiert und gut ist. Auf die Weise haben wir zwar wieder diesen 0.01 sekunden Abstand, aber anstatt in diesem Abstand ständig alle Daten zu synchronisieren, wird nur dieses Hilfs-dictionary synchron gehalten.

Also nochmal der Aufbau:
Ein "Haupt"-Prozess, welcher alle möglichen Daten von APIs abruft und in self. Variablen speichert.
Viele (bis zu 100 oder mehr, aber für den Anfang eher 10) weitere Prozesse, die sich ganz bestimmte dieser Daten vom Haupt-prozess holen, jeweils zb alle 5-10 sekunden.
Der Aufbau ist deshalb so gewählt, weil zb jeweils 10 von 100 dieser Prozesse dieselben Daten brauchen, es macht also keinen Sinn, dass alle 10 unabhängig voneinander dieselben Daten via API abfragen (auch schon wegen des API Call Limits)
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wir haben hier schon weiter oben Queues als Mittel des Austauschs besprochen. Die sind nach wie vor das Mittel der Wahl. Das Gerede von self-Variablen zeigt, das du da noch ganz grosse konzeptionelle Luecken hast. Ueber eine Queue kann sowohl ein Kind Daten anfordern, als auch geliefert bekommen. Den Zustand, den ein Objekt zufaellig hatte zum Zeitpunkt des Forks, kann und sollte man nicht als Grundlage dafuer nehmen, was spaeter dann zu tun ist. 100 Prozesse zu starten klingt ebenfalls sehr falsch - das ist viel zu viel, ausser du hast ein wirklich dickes System. Und selbst dann hat es keine Gewinne bezueglich des zu erzielenden Durchsatzes, sondern bestenfalls konzeptionell. Viel besser ist ein arbeiten mit asynchronen Anfragen. Auf die Art liefert auch ein *einziger* NGINX-Prozess tausenden Clients gleichzeitig Daten. Damit hat man auch ploetzlich kein Problem mehr damit, dass man eine laufende Abfrage hat, waehrend man gleichzeitig das Rate-Limit eines anderen Servers ausnutzen will, weil man Timer und Verbindungen kombinieren kann. Etc etc etc.

Ich weiss ja das du gerne ein Geheimnis machst um was du da tust, aber ganz ehrlich: dieses Gefrickel und rumgerate an dem man sich hier beteiligen soll, ohne dass einem klar ist, was du eigentlich fuer ein Problem hast, bringt nix.
Benutzeravatar
noisefloor
User
Beiträge: 3853
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

wie __deets__ schon sagt: die Queue ist das Mittel der Wahl zur Kommunikation zwischen Python-Prozessen.

Ggf. solltest du als gemeinsamen Datenspeicher auch mal über z.B. Redis (ein KV-Store, dass für solche Anwendungsfälle gemacht ist) nachdenken.
Ob das hier wirklich Sinn macht, lässt sich aufgrund der vagen Informationslage schlechten.

Viele asynchrone API-Calls über's Netz spricht stark für den Einsatz von asyncio (oder einem äquivalenten Modul). Das ist genau für sowas gemacht. Setzt allerdings Python >= 3.5 voraus.

Gruß, noisefloor
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: 14522
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: 14522
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: 14522
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.
Antworten