14 python http twisted download
我正在使用Python/Twisted的Web应用程序.
我希望用户能够下载一个非常大的文件(> 100 Mb).当然,我不想将所有文件加载到(服务器的)内存中.
服务器端我有这个想法:
...
request.setHeader('Content-Type', 'text/plain')
fp = open(fileName, 'rb')
try:
r = None
while r != '':
r = fp.read(1024)
request.write(r)
finally:
fp.close()
request.finish()
Run Code Online (Sandbox Code Playgroud)
我希望这可以工作,但我有问题:我正在测试FF ...似乎浏览器让我等到文件完成下载,然后我有打开/保存对话框.
我立即预期对话框,然后进行操作进度条...
也许我必须在Http标题中添加一些东西......有点像文件的大小?
Jea*_*one 35
您发布的示例代码的两个大问题是它是非合作的,它在发送之前将整个文件加载到内存中.
while r != '':
r = fp.read(1024)
request.write(r)
Run Code Online (Sandbox Code Playgroud)
请记住,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
Run Code Online (Sandbox Code Playgroud)
您可以NOT_DONE_YET在我的博客http://jcalderone.livejournal.com/50562.html(特别参见"异步响应"条目)中阅读更多关于"60秒内的Twisted Web"系列的相关想法和其他相关想法.