4 Stimmen

mod_wsgi liefert Ausgabepuffer statt Rückgabe

Im Moment habe ich ein mod_wsgi-Skript, das wie folgt strukturiert ist

def application(environ, start_response):
    status = '200 OK'
    output = 'Hello World!'

    response_headers = [('Content-type', 'text/plain'),
                    ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    return [output]

Ich frage mich, ob jemand eine Möglichkeit kennt, dies zu ändern, um mit einer yield Basis anstelle von return Auf diese Weise kann ich die Seite senden, während sie generiert wird, und nicht erst, wenn sie fertig ist, so dass das Laden der Seite für den Benutzer schneller geht.

Wenn ich jedoch die Ausgabe gegen eine Liste austausche und sie in der Anwendung() ausgeben lasse, tritt ein Fehler auf:

TypeError: sequence of string values expected, value of type list found

7voto

nosklo Punkte 204121
def application(environ, start_response):
    status = '200 OK'
    output = 'Hello World!'

    response_headers = [('Content-type', 'text/plain'),
                    ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    yield output

"Wenn ich jedoch die Ausgabe gegen eine Liste austausche und sie in der Anwendung() ausgibt, wird ein Fehler ausgegeben:"

Nun, geben Sie die Liste nicht her. Geben Sie stattdessen jedes Element aus:

for part in mylist:
    yield part

oder, wenn die Liste der gesamte Inhalt ist, einfach:

return mylist

Denn die Liste ist bereits ein Iterator und kann sich von selbst ergeben.

7voto

Graham Dumpleton Punkte 56087

Beachten Sie, dass "Ausbeute" vermieden werden sollte, wenn es nicht unbedingt notwendig ist. Insbesondere ist "yield" ineffizient, wenn viele kleine Strings ausgegeben werden. Das liegt daran, dass die WSGI-Spezifikation vorschreibt, dass nach jeder übergebenen Zeichenkette die Antwort geleert werden muss. Für Apache/mod_wsgi bedeutet flushing, dass jeder String durch die Apache Output Bucket Brigade und das Filtersystem auf den Socket gezwungen wird. Wenn man den Overhead des Apache-Ausgabefiltersystems ignoriert, ist das Schreiben vieler kleiner Strings auf einen Socket einfach nur schlecht.

Dieses Problem besteht auch, wenn ein Array von Strings von einer Anwendung zurückgegeben wird, da zwischen den einzelnen Strings im Array ebenfalls ein Flush durchgeführt werden muss. Dies liegt daran, dass die Zeichenkette als Iterable und nicht als Liste behandelt wird. Daher ist es bei einer vorgefertigten Liste von Strings viel besser, die einzelnen Strings zu einem großen String zusammenzufassen und eine Liste zurückzugeben, die nur diesen einen String enthält. Auf diese Weise kann eine WSGI-Implementierung auch automatisch eine Content-Length für die Antwort generieren, wenn diese nicht explizit angegeben wurde.

Vergewissern Sie sich nur, dass beim Zusammenfügen aller Zeichenketten in einer Liste das Ergebnis in einer Liste zurückgegeben wird. Wenn dies nicht der Fall ist und stattdessen die Zeichenkette zurückgegeben wird, wird diese Zeichenkette als Iterable behandelt, wobei jedes Element der Zeichenkette eine einzelne Zeichenkette ist. Dies führt dazu, dass nach jedem Zeichen ein Flush durchgeführt wird, was noch schlimmer ist, als wenn die Zeichenketten nicht zusammengefügt worden wären.

0voto

Aaron Watters Punkte 2654

Senden Sie nicht die Länge des Inhalts, sondern die Ausgabe so, wie Sie sie ableiten. Sie brauchen die Größe der Ausgabe nicht zu kennen, wenn Sie einfach nicht den Content-Length-Header nicht senden. Auf diese Weise können Sie einen Teil der Antwort senden senden, bevor Sie den Rest der Antwort errechnet haben.

def application(environ, start_response):
    status = '200 OK'
    output = 'Hello World!'

    response_headers = [('Content-type', 'text/html')]
    start_response(status, response_headers)

    yield head()
    yield part1()
    yield part2()
    yield part3()
    yield "<!-- bye now! -->"

Andernfalls bringt das Senden in Paketen keinen Nutzen, da das Berechnen der Ausgabe wahrscheinlich der langsamste Teil ist und das Internetprotokoll die Ausgabe ohnehin in Blöcken sendet.

Leider funktioniert dies nicht, wenn zum Beispiel die Berechnung von part2() entscheidet, dass Sie wirklich eine Kopfzeile (wie ein Cookie) ändern müssen oder andere seitenglobale Datenstrukturen aufbauen muss -- wenn dies jemals passiert, müssen Sie die gesamte Ausgabe berechnen, bevor die Kopfzeilen zu senden, und könnte genauso gut eine return [output]

Zum Beispiel http://aaron.oirt.rutgers.edu/myapp/docs/W1200_1200.config_template Erforderlich ist der Aufbau einer globalen Datenstruktur für die Links zu den Unterabschnitten die oben auf der Seite angezeigt werden - der letzte Unterabschnitt muss also gerendert werden gerendert werden, bevor der erste Teil der Ausgabe an den Client übermittelt wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X