Две большие проблемы с размещенным вами примером кода заключаются в том, что он не взаимодействует и загружает весь файл в память перед отправкой.
while r != '':
r = fp.read(1024)
request.write(r)
Помните, что Twisted использует совместную многозадачность для достижения любого вида параллелизма. Итак, первая проблема с этим фрагментом состоит в том, что это цикл while над содержимым всего файла (который, как вы говорите, большой). Это означает, что весь файл будет считан в память и записан в ответ до того, как что-либо еще может произойти в процессе. В этом случае случается так, что « что-нибудь » также включает в себя передачу байтов из буфера в памяти в сеть, поэтому ваш код также будет хранить весь файл в памяти сразу и только начнет избавляться об этом, когда этот цикл завершается.
Так что, как правило, вы не должны писать код для использования в приложении на основе Twisted, которое использует такой цикл для большой работы. Вместо этого вам нужно выполнять каждую небольшую часть большой работы таким образом, чтобы она взаимодействовала с циклом событий. Для отправки файла по сети лучше всего подойти к этому с производителями и потребителями . Это два связанных API для перемещения больших объемов данных с использованием пустых событий буфера, чтобы сделать это эффективно и без лишних затрат памяти.
Вы можете найти некоторую документацию по этим API здесь:
http://twistedmatrix.com/projects/core/documentation/howto/producers.html
К счастью, для этого очень распространенного случая уже есть продюсер, который вы можете использовать вместо того, чтобы реализовывать свой собственный:
http://twistedmatrix.com/documents/current/api/twisted.protocols.basic.FileSender.html
Вы, вероятно, хотите использовать это примерно так:
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
Вы можете узнать больше о NOT_DONE_YET
и других связанных с этим идеях из серии «Витая сеть за 60 секунд» в моем блоге, http://jcalderone.livejournal.com/50562.html (см., В частности, записи «Асинхронные ответы»).