Zwei große Probleme mit der Beispielcode, den Sie gepostet haben, ist, dass es nicht kooperativ ist und es die gesamte Datei in den Speicher lädt, bevor es gesendet wird.
while r != '':
r = fp.read(1024)
request.write(r)
Denken Sie daran, dass Twisted kooperatives Multitasking verwendet, um jede Art von Nebenläufigkeit zu erreichen. Also das erste Problem mit diesem Snippet ist, dass es eine while-Schleife über den Inhalt einer ganzen Datei ist (von der Sie sagen, dass sie groß ist). Dies bedeutet, dass die gesamte Datei in den Speicher gelesen und in die Antwort geschrieben wird, bevor irgendetwas sonst kann in dem Prozess passieren. In diesem Fall passiert es, dass "irgendwas" auch das Schieben der Bytes aus dem In-Memory-Puffer auf das Netzwerk beinhaltet, so dass Ihr Code auch die gesamte Datei im Speicher hält und sie nur dann los wird, wenn dies geschieht Schleife wird abgeschlossen.
Also, als allgemeine Regel sollten Sie nicht Code für die Verwendung in einer Twisted-basierten Anwendung schreiben, die eine Schleife wie diese verwendet, um eine große Arbeit zu tun. Stattdessen müssen Sie jedes kleine Stück des großen Auftrags so bearbeiten, dass es mit der Ereignisschleife zusammenarbeitet. Für das Senden einer Datei über das Netzwerk ist der beste Weg, dies zu erreichen, mit Produzenten und Verbraucher. Dies sind zwei verwandte APIs zum Verschieben großer Datenmengen mithilfe leerer Pufferereignisse, um sie effizient und ohne unnötige Speichermengen zu verarbeiten.
Sie eine Dokumentation dieser APIs finden Sie hier:
http://twistedmatrix.com/projects/core/documentation/howto/producers.html
Zum Glück für diese sehr häufigen Fall, gibt es auch ein Hersteller bereits geschrieben, dass Sie verwenden können, anstatt Ihre eigene Implementierung:
http://twistedmatrix.com/documents/current/api/twisted.protocols.basic.FileSender.html
Sie wollen wahrscheinlich es so eine Art verwenden:
from twisted.protocols.basic import FileSender
from twisted.python.log import err
from twisted.web.server import NOT_DONE_YET
class Something(Resource):
...
def render_GET(self, request):
request.setHeader('Content-Type', 'text/plain')
fp = open(fileName, 'rb')
d = FileSender().beginFileTransfer(fp, request)
def cbFinished(ignored):
fp.close()
request.finish()
d.addErrback(err).addCallback(cbFinished)
return NOT_DONE_YET
Sie können mehr über NOT_DONE_YET
und andere verwandte Ideen die "Twisted Web in 60 Sekunden" -Serie auf meinem Blog, http://jcalderone.livejournal.com/50562.html (siehe die "asynchrone Antworten" Einträge insbesondere). Hier
Sie werden wahrscheinlich einen besseren Durchsatz und weniger Last auf dem Server erhalten, indem das Lesen und Senden größere Stücke ... experimentiere mit Werten um 4-16k, um herauszufinden, was für deine Umstände am besten geeignet ist. – dcrosta
Möchten Sie eine der Antworten akzeptieren? –