I have the following Werkzeug application for returning a file to the client:
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
The part I want to focus on is this one:
response = Response( response=fileObj.read() )
In this case the response takes about 500 ms (C:\test.pdf
is a 4 MB file. Web server is in my local machine).
But if I rewrite that line to this:
response = Response()
response.response = fileObj
Now the response takes about 1500 ms. (3 times slower)
And if write it like this:
response = Response()
response.response = fileObj.read()
Now the response takes about 80 seconds (that's right, 80 SECONDS).
Why is there that much difference between the 3 methods?
And why is the third method sooooo slow?
The answer to that is pretty simple:
x.read()
<- reads the whole file into memory, inefficientresponse
to a string: bad idea. It's an iterator as mentioned before, so you are now sending each character in the string as a separate packet.The correct solution is to wrap the file in the file wrapper provided by the WSGI server:
from werkzeug.wsgi import wrap_file
return Response(wrap_file(environ, yourfile), direct_passthrough=True)
The direct_passthrough
flag is required so that the response object does not attempt to iterate over the file wrapper but leaves it untouched for the WSGI server.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With