2013-05-27 70 views
4

我有一個文件返回給客戶端以下WERKZEUG應用: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 ms(C:\test.pdf是一個4 MB文件,Web服務器位於本地計算機中)。

但是,如果我重寫該行這樣的:

response = Response() 
response.response = fileObj 

現在,響應時間爲1500毫秒。 (慢3倍)

如果它這樣寫:

response = Response() 
response.response = fileObj.read() 

現在,響應時間爲80秒(這是正確的,80秒)。

爲什麼3種方法之間有很大差異?
爲什麼第三種方法sooooo很慢?

回答

4

經過一番測試後,我想我已經弄清楚了這個神祕莫測。

@Armin已經解釋了爲什麼這...

response = Response() 
response.response = fileObj.read() 

...是如此之慢。但這並不能解釋爲什麼這...

response = Response(response=fileObj.read()) 

...是如此之快。他們似乎是同一件事,但顯然他們不是。否則就不會有速度的巨大差異。

這裏的關鍵是在文檔的這一部分:http://werkzeug.pocoo.org/docs/wrappers/

響應可以是任何類型的迭代或字符串。如果它是一個字符串,它被認爲是一個迭代器,其中一個是傳遞的字符串。

即,當您給構造函數一個字符串時,它將被轉換爲一個可迭代的字符串,它僅僅是元素。但是當你這樣做:response.response = fileObj.read(),字符串被視爲是。

所以,使其行爲類似於構造函數,你必須這樣做:

response.response = [ fileObj.read() ] 

現在的文件以最快的速度送到越好。

8

這個問題的答案是很簡單:

  • x.read() < - 讀取整個文件到存儲器中,低效
  • 設置響應到一個文件:非常低效的,因爲該對象的協議是一個迭代。所以你會逐行發送文件。如果它是二進制的,你甚至會發送它隨機的塊大小。
  • response設置爲字符串:壞主意。它是前面提到的迭代器,因此您現在將字符串中的每個字符作爲單獨的數據包發送。

正確的解決辦法是包裝在文件中由WSGI服務器所提供的文件包裝:

from werkzeug.wsgi import wrap_file 
return Response(wrap_file(environ, yourfile), direct_passthrough=True) 

使得響應對象並不試圖遍歷文件包裝的direct_passthrough標誌被要求但對WSGI服務器沒有影響。

+0

我顯示的第一個方法:'Response(response = fileObj.read())'設置字符串的響應,它只需要500毫秒。這對我來說似乎相當快。 – GetFree