Python's asyncore um periodisch Daten mit einem Variablen Timeout zu senden. Gibt es einen besseren Weg?

8

Ich wollte einen Server schreiben, mit dem sich ein Client verbinden und regelmäßige Updates erhalten konnte, ohne abfragen zu müssen. Das Problem, das ich mit asyncore hatte, ist, dass wenn Sie nicht zurückgeben, wenn dispatcher.writable () aufgerufen wird, Sie warten müssen, bis das asyncore.loop abgelaufen ist (Standard ist 30s).

Die zwei Möglichkeiten, die ich versucht habe, dies zu umgehen, sind 1) die Zeitüberschreitung auf einen niedrigen Wert zu reduzieren oder 2) Verbindungen abzufragen, wann sie das nächste Mal aktualisieren und einen angemessenen Zeitüberschreitungswert erzeugen. Wenn Sie jedoch in 'man 2 select_tut' auf 'Select Law' verweisen, heißt es: "Sie sollten immer select () ohne Timeout verwenden."

Gibt es einen besseren Weg, dies zu tun? Twisted vielleicht? Ich wollte versuchen, zusätzliche Threads zu vermeiden. Ich werde das Beispiel für die Zeitlimitüberschreitung hier einfügen:

%Vor%     
Nick Sonneveld 24.06.2009, 06:11
quelle

5 Antworten

4

Das "select law" gilt nicht für Ihren Fall, da Sie nicht nur vom Client ausgelöste (reine Server-) Aktivitäten, sondern auch zeitgesteuerte Aktivitäten haben - genau dafür ist das select timeout vorgesehen. Was das Gesetz wirklich sagen sollte ist, "wenn Sie eine Zeitüberschreitung angeben, stellen Sie sicher, dass Sie etwas Nützliches tun müssen, wenn die Zeitüberschreitung eintritt". Das Gesetz soll vor vielbeschäftigtem Warten schützen; Dein Code ist nicht beschäftigt - warte.

Ich würde _timeout nicht auf das Maximum von 0.1 und die nächste Aktualisierungszeit setzen, sondern auf das Maximum von 0.0 und das nächste Timeout. Wenn ein Aktualisierungszeitraum während der Aktualisierung abgelaufen ist, sollten Sie dieses spezielle Update sofort durchführen.

Anstatt jeden Kanal jedes Mal zu fragen, ob er aktualisieren möchte, könnten Sie alle Kanäle in einer Prioritätswarteschlange speichern (sortiert nach der nächsten Aktualisierungszeit) und dann nur für die ersten Kanäle updaten (bis Sie eine Aktualisierung finden die Zeit ist nicht angekommen). Sie können dafür das heapq-Modul verwenden.

Sie können auch einige Systemaufrufe speichern, indem Sie nicht für jeden Kanal nach der aktuellen Uhrzeit fragen, sondern nur einmal die aktuelle Uhrzeit abfragen und an update übergeben.

    
Martin v. Löwis 24.06.2009, 07:10
quelle
4

Vielleicht kannst du das mit sched.scheduler machen, so (n.b. nicht getestet):

%Vor%     
demiurgus 24.04.2010 07:56
quelle
2

Dies ist im Grunde die Lösung des Demiurgus mit den abgerundeten Ecken. Er behält seine Grundidee bei, verhindert aber RuntimeErrors und Busy Loops und wird getestet. [Edit: behobene Probleme beim Ändern des Schedulers während _delay]

%Vor%     
Helmut Grohne 10.02.2011 12:08
quelle
1

Ich würde Twisted verwenden, lange Zeit, seit ich Asyncore benutzt habe, aber ich denke, das sollte das verdrehte Äquivalent sein (nicht getestet, aus dem Gedächtnis geschrieben):

%Vor%     
truppo 24.06.2009 07:38
quelle
0

Vielleicht verstehe ich nicht, was das OP zu erreichen versucht, aber ich habe dieses Problem gelöst, indem ich einen Thread verwende, der eine Schwachstelle jedes Channel- (asyncore.dispatcher) Objekts erhält. Dieser Thread bestimmt sein eigenes Timing und sendet dem Kanal periodisch eine Aktualisierung unter Verwendung einer Warteschlange in diesem Kanal. Er ruft die Warteschlange vom Channel-Objekt ab, indem er getQueue aufruft.

Der Grund, warum ich eine Schwachstelle verwende, ist, dass Clients vorübergehend sind. Wenn der Kanal abstirbt, gibt die Schwachstelle None zurück. Auf diese Weise behält der Timing-Thread alte Objekte nicht am Leben, weil sie auf sie verweisen.

Ich weiß, dass das OP Threads vermeiden wollte, aber diese Lösung ist sehr einfach. Es erstellt immer nur einen Thread und spricht mit allen Kanälen, die erstellt werden, wenn das Server-Objekt sie der Liste der zu überwachenden Objekte hinzufügt.

    
Demolishun 10.07.2011 09:55
quelle

Tags und Links