Hallo Forum.
Zunächst die Umgebung: Ich habe einen ThreadedTCPServer mit einem eigenen Protokol (im prinzip was jasonartiges).
Eine Clientconnection wird aufrecht erhalten, d.H. sie wird nicht nur für eine Anfrage wie bei HTTP(1.0) genutzt.
In einem weiteren Thread läuft ein Spiel.
Die Workerthreads parsen die eingehenden Daten und legen Nachrichten auf einen Queue im Spiel.
Das Spiel arbeitet seinen Queue ab, und legt Nachrichten auf die Queues der Workerthreads, die diese dann kodiert raussenden.
Hier erstmal Stop, wenn diese Architektur Müll ist, bitte nicht weiterlesen und sie stattdessen sofort zerreissen.
So, mein Problem ist nun, dass der Workerthread nicht weis, ob er als nächstes empfängt oder sendet. Zz. durchläuft er eine Schleife, in der er zuerst ein non-blocking-read auf dem socket macht, dann ein non-blocking get auf den queue. (hätte ich zwei Sockets, wäre vmtl select mein freund, aber ich hab ja nur einen). Das sieht nach "idle wait aus".
In einer Alternativlösung hab ich dem Workerthread einen zweiten Thread gegeben, der workerthread hat gelesen, der andere geschrieben. Das sieht nach Threadoverkill aus.
Das ganze ist so unausprechlich hässlich, aber mir fällt da nichts besseres ein, u.A. auch aufgrund mangeldem Wissen über Netzwerkdinge (ich finde da irgendwie nur c-tutorials, nie was abstrakteres).
Wie sähe ein besseres Design aus?
ThreadedTCPServer, asynchrones senden
-
- User
- Beiträge: 773
- Registriert: Mittwoch 5. November 2003, 18:06
- Wohnort: Schweiz
- Kontaktdaten:
Hi
Also ein select würde sich auch hier anbieten.
Pseudocode:
So würde ich das lösen.
*edit* vielleicht kannst du auch von hier abgucken: http://www.python-forum.de/post-76767.html
Gruss
Also ein select würde sich auch hier anbieten.
Pseudocode:
Code: Alles auswählen
while 1:
lesbare_sockets = [socket]
schreibbare_sockets = []
if queue_len > 0: #wichtig, da sonst select immer gleich den schreibbaren socket zurückgibt, auch wenn keine daten anliegen
schreibbare_sockets.append(socket)
r,w,e = select(lesbare_sockets, schreibbare_sockets, [socket], 0.01)
if r:
print 'daten können gelesen werden'
if w:
print 'daten können gesendet werden'
*edit* vielleicht kannst du auch von hier abgucken: http://www.python-forum.de/post-76767.html
Gruss
Danke erstmal für die Antwort.
In deinem Beispiel hast du einen select-timeout von 0.01, d.H. es werden maximal 100 Nachrichten(mengen) pro sekunde gesendet.
Gibt es irgendwelchen empfehlenswerten Lesestoff für Netzwerk/Socket-sachen, die nicht auf "so öffne ich sockets" rauslaufen, sondern eher so "best practices" sind?
Um das Problem, herauszukriegen, ob ich lesen oder schreiben kann, zu lösen, ja. Das Problem, was ich sehe (was aber möglicherweise nicht existiert), ist, dass ich eine Schleife habe, die die ganze Zeit den Queue fragt, ob er denn was hat. Das sieht so auf den ersten Blick etwas ineffizient aus.rayo hat geschrieben:Also ein select würde sich auch hier anbieten.
In deinem Beispiel hast du einen select-timeout von 0.01, d.H. es werden maximal 100 Nachrichten(mengen) pro sekunde gesendet.
Wenn ich das richtig verstehe, wird die on_write immer aufgerufen, wenn was geschrieben werden könnte. was ja vermutlich so gut wie immer ist, da ich eher selten was auf dem queue hab. Das sieht für mich erstmal ineffizient aus, oder bilde ich das mir nur ein?*edit* vielleicht kannst du auch von hier abgucken: http://www.python-forum.de/post-76767.html
Gibt es irgendwelchen empfehlenswerten Lesestoff für Netzwerk/Socket-sachen, die nicht auf "so öffne ich sockets" rauslaufen, sondern eher so "best practices" sind?
Hab ich, sehe aber nicht direkt, wo das hilfreich sein kann. Ayncore scheint davon auszugehen, dass ich immer schreiben will, wenns möglich ist (handle_write).veers hat geschrieben:Schau dir doch mal asyncore / asynchat an
Darf ich, umgekehrt, aus den Tipps schliessen, dass eine Schleife
Code: Alles auswählen
while True:
r, w, e = select.select([self.sock],[self.sock], [], 0)
if r:
msg = parse(self.sock.read(1024))
game.queue.put(msg)
if w:
try:
msg = self.queue.get(timeout=0)
except Empty:
pass
else:
self.sock.write(str(msg))
keine soo schlechte idee ist? (ist ziemlich genau das, was ich zZ habe, von namen und sendbuffering mal abgesehen)
- veers
- User
- Beiträge: 1219
- Registriert: Mittwoch 28. Februar 2007, 20:01
- Wohnort: Zürich (CH)
- Kontaktdaten:
keppla hat geschrieben:Hab ich, sehe aber nicht direkt, wo das hilfreich sein kann. Ayncore scheint davon auszugehen, dass ich immer schreiben will, wenns möglich ist (handle_write).veers hat geschrieben:Schau dir doch mal asyncore / asynchat an
http://docs.python.org/dev/library/asyn ... r.writable
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Ja, und? Ist es wünschenswert, dass x mal die sekunde eine Funktion queue.empty() aufgerufen wird?veers hat geschrieben:keppla hat geschrieben:Hab ich, sehe aber nicht direkt, wo das hilfreich sein kann. Ayncore scheint davon auszugehen, dass ich immer schreiben will, wenns möglich ist (handle_write).veers hat geschrieben:Schau dir doch mal asyncore / asynchat an
http://docs.python.org/dev/library/asyn ... r.writable
Wenn ich diese select-sache richtig verstanden habe (was ich ja scheinbar nicht habe), dient die doch dazu, auf eine prozessorzeitschonende Art den thread immer nur dann wiederzubeleben, wenn es was zu tun gibt (wenn sie returned). Eben das wäre aber nicht der Fall, wenn ich die ganze zeit den queue frag, ob es was zu tun gibt, und den select sofort returnen lasse.
Bitte entschuldigt meine Langsamkeit, was das Verstehen angeht.rayo hat geschrieben:Es ist wünschenswert dass select nur auf schreiben prüft wenn auch nur Daten anliegen. darum writable, ist bei asyncore und bei meinem wrapper gleich.
Es ist also Lasttechnisch OK, wenn man viele Threads hat, die in einer Endlosschleife laufen, und dauernd was tun (queue.empty()), es ist aber schlecht, wenn in einem select mehr sockets als nötig werden?
Das ganze sieht für mich so nach "idle wait" aus.
Danke für eure Geduld

-
- User
- Beiträge: 773
- Registriert: Mittwoch 5. November 2003, 18:06
- Wohnort: Schweiz
- Kontaktdaten:
Hi
Du hast für die Netzwerkkommunikation folgendes:
1 Thread, der ein select ausführt, egal wie viele sockets
Hier dein Beispiel ein wenig geändert. Die Unterschiede:
Wenn keine Daten vorhanden sind, macht er im 10ms Tackt die Überprüfung ob neue Daten anliegen oder nicht, die 10ms Wartezeit verbringt er mit der Überprüfung auf neue eingehende Daten.
Soweit ich weiss, ist das üblich bei non-blocking sockets.
Gruss
Du hast für die Netzwerkkommunikation folgendes:
1 Thread, der ein select ausführt, egal wie viele sockets
Hier dein Beispiel ein wenig geändert. Die Unterschiede:
- * der Socket wird nur auf writable geprüft wenn auch Daten vorhanen sind zum schreiben
* bei queue.get() braucht es kein nonblocked get mehr weil wenn er dort hin kommt immer Daten in der Queue sind
* select nicht sofort beenden lassen (timeout so 0.01s)
Code: Alles auswählen
while True:
w_socks = []
if self.queue.qsize() > 0:
w_socks = [self.sock]
r, w, e = select.select([self.sock],w_socks, [], 0.01)
if r:
msg = parse(self.sock.read(1024))
game.queue.put(msg)
if w:
msg = self.queue.get()
self.sock.write(str(msg))
Soweit ich weiss, ist das üblich bei non-blocking sockets.
Gruss