我有以下Werkzeug应用程序将文件返回给客户端:
from werkzeug.wrappers import Request, Response
@Request.application
def application(request):
fileObj = file(r'C:\test.pdf','rb')
response = Response( response=fileObj.read() )
response.headers['content-type'] = 'application/pdf'
return response
我想关注的部分是这一部分:
response = Response( response=fileObj.read() )
在这种情况下,响应大约需要500毫秒(C:\test.pdf
是一个4 MB的文件.Web服务器在我的本地计算机中。)
但是,如果我重写这一行:
response = Response()
response.response = fileObj
现在响应大约需要1500毫秒。 (慢3倍)
如果这样写:
response = Response()
response.response = fileObj.read()
现在响应大约需要80秒(这是正确的,80 SECONDS)。
为什么3种方法之间存在很大差异?
为什么第三种方法太慢?
答案 0 :(得分:8)
答案很简单:
x.read()
< - 将整个文件读入内存,效率低下response
设置为字符串:糟糕的主意。它是前面提到的迭代器,因此您现在将字符串中的每个字符作为单独的数据包发送。正确的解决方案是将文件包装在WSGI服务器提供的文件包装器中:
from werkzeug.wsgi import wrap_file
return Response(wrap_file(environ, yourfile), direct_passthrough=True)
需要direct_passthrough
标志,以便响应对象不会尝试迭代文件包装器,但不会使WSGI服务器保持不变。
答案 1 :(得分:4)
经过一些测试后,我想我已经弄明白了。
@Armin已经解释了为什么......
response = Response()
response.response = fileObj.read()
......太慢了。但这并不能解释为什么会这样......
response = Response( response=fileObj.read() )
......太快了。它们似乎是一样的,但显然它们不是。否则就不会有那么大的差异。
这里的关键是文档的这一部分:http://werkzeug.pocoo.org/docs/wrappers/
响应可以是任何类型的可迭代或字符串。如果它是一个字符串,它被认为是一个可迭代的,其中一个项目是传递的字符串。
即。当你给构造函数一个字符串时,它被转换为一个iterable,字符串是它唯一的元素。但是当你这样做:response.response = fileObj.read()
时,字符串被视为原样。
因此,为了使其行为与构造函数一样,您必须这样做:
response.response = [ fileObj.read() ]
现在文件尽快发送。
答案 2 :(得分:1)
我无法准确回答为何会出现这种情况,但http://werkzeug.pocoo.org/docs/wsgi/#werkzeug.wsgi.wrap_file可能有助于解决您的问题。