通常一個人首先關心的是編寫代碼的作品,它的邏輯功能根據需要產生預期的輸出。但是,有時這還不足以使代碼高效地工作。
在這種情況下,需要的是某種東西-實際上,通常是一系列東西-可以提高代碼的性能,而又不會,或者僅以最小的方式影響代碼的行為。
清楚了解“性能”的含義很重要。不僅有一個指標。
提高速度可能是程序最明顯的目標,但有時可能會尋求其他性能改進,例如降低內存消耗或減少對數據庫或網絡的需求。
一個方面的改進通常會帶來另一方面的改進,但并非總是如此;有時一個人甚至可以犧牲另一個人。例如,程序速度的提高可能會導致它使用更多的內存。更糟糕的是,這可能是自欺欺人的-如果速度提升如此之耗內存,以至于系統(tǒng)開始耗盡內存,那么您的弊大于利。
還有其他需要權衡的方面。您自己的時間是寶貴的資源,比CPU時間更寶貴。有些改進可能太難了,不值得實施,或者可能影響代碼的可移植性或可維護性。并非所有的性能改進都值得付出努力。
因此,您需要知道要實現哪些性能改進,并且還需要知道有充分的理由朝著這個方向瞄準-并且您需要:
僅僅猜測或假設效率低下在代碼中是沒有用的。
django-debug-toolbar是一個非常方便的工具,可以深入了解您的代碼在做什么以及花了多少時間。特別是,它可以顯示頁面生成的所有SQL查詢以及每個查詢花費了多長時間。
工具欄也可以使用第三方面板,該面板可以(例如)報告緩存性能和模板渲染時間。
有許多免費服務可以從遠程HTTP客戶端的角度分析和報告站點頁面的性能,實際上是在模擬實際用戶的體驗。
這些無法報告您的代碼內部,但可以提供有用的洞察力來了解您網站的整體性能,包括無法在Django環(huán)境中充分衡量的方面。示例包括:
還有一些付費服務執(zhí)行類似的分析,其中包括一些支持Django的服務,這些服務可以與您的代碼庫集成以更全面地分析其性能。
優(yōu)化方面的某些工作涉及解決性能缺陷,但是某些工作也可以內置于您要做的事情中,這是您甚至在開始考慮提高性能之前就應該采用的良好實踐的一部分。
在這方面,Python是一種出色的語言,因為外觀優(yōu)美且感覺正確的解決方案通常是性能最好的解決方案。與大多數技能一樣,學習“看起來正確”的東西需要練習,但是最有用的準則之一是:
Django提供了許多不同的處理方式,但是僅僅因為可以以某種方式做某事并不意味著這是最合適的方式。例如,您可能會發(fā)現您可以在QuerySet,Python或模板中計算相同的東西-集合中的項目數,也許 。
但是,在較低級別而不是較高級別進行此工作幾乎總是會更快。在更高的層次上,系統(tǒng)必須通過多層抽象和機器層次來處理對象。
也就是說,數據庫通??梢员萈ython更快地完成任務,而Python可以比模板語言更快地完成任務:
# QuerySet operation on the database # fast, because that's what databases are good at my_bicycles.count() # counting Python objects # slower, because it requires a database query anyway, and processing # of the Python objects len(my_bicycles) # Django template filter # slower still, because it will have to count them in Python anyway, # and because of template language overheads {{ my_bicycles|length }}
一般而言,最適合該工作的級別是適合編寫代碼的最低級別。
注意
上面的示例僅是說明性的。
首先,在現實生活中,您需要考慮計數前后發(fā)生的事情,以找出在特定情況下執(zhí)行此操作的最佳方法。數據庫優(yōu)化文檔描述了一種情況,在這種情況下,模板中的計數會更好。
其次,還有其他選擇要考慮:在實際情況下,直接從模板調用方法可能是最合適的選擇。{{ my_bicycles.count }}QuerySet count()
通常,計算值很昂貴(即耗費資源且速度很慢),因此將值保存到可快速訪問的緩存中以備下次使用時會產生巨大的好處。
Django具有完善的緩存框架以及其他較小的緩存功能,這是一項足夠重要且功能強大的技術。
Django的緩存框架通過保存動態(tài)內容,因此無需為每個請求進行計算,就為提高性能提供了非常重要的機會。
為了方便起見,Django提供了不同級別的緩存粒度:您可以緩存特定視圖的輸出,或者僅緩存難以生成的片段,甚至整個站點。
實施緩存不應被視為改善性能不佳的代碼的替代方法,因為它的編寫質量很差。這是生成性能良好的代碼的最后步驟之一,而不是捷徑。
通常必須多次調用一個類實例的方法。如果該功能很昂貴,那么這樣做會很浪費。
使用cached_property裝飾器可以保存屬性返回的值。下次在該實例上調用該函數時,它將返回保存的值,而不是重新計算它。請注意,這僅適用于將self參數作為唯一參數的方法,并將方法更改為屬性。
某些Django組件也具有自己的緩存功能;這些將在下面與那些組件相關的部分中討論。
懶惰是對緩存的一種補充策略。緩存通過保存結果來避免重新計算。懶惰會延遲計算,直到真正需要它為止。
惰性允許我們在實例化它們之前,甚至在可能實例化它們之前都引用它們。這有許多用途。
例如,可以在甚至不知道目標語言之前就使用惰性翻譯,因為直到真正需要翻譯后的字符串(例如在渲染的模板中)時,它才發(fā)生。
懶惰也是一種通過首先避免工作來節(jié)省精力的方法。就是說,懶惰的一個方面是什么也要做,直到必須要做,因為畢竟可能沒有必要。因此,懶惰可能會影響性能,并且相關工作的成本越高,通過懶惰獲得的收益就越大。
Python提供了許多用于懶惰求值的工具,尤其是通過 生成器和生成器表達式構造。值得閱讀Python的惰性,以發(fā)現在代碼中使用惰性模式的機會。
Django本身很懶。在的評估中可以找到一個很好的例子QuerySets。QuerySet是惰性的。因此,QuerySet可以創(chuàng)建,傳遞和與其他對象組合使用 QuerySets,而無需實際進行任何數據庫訪問以獲取其描述的項目。傳遞的是QuerySet對象,而不是數據庫最終需要的項目集合。
另一方面,某些操作將強制評估QuerySet。避免過早評估a QuerySet可以節(jié)省對數據庫的昂貴而不必要的行程。
Django還提供了一個keep_lazy()裝飾器。這允許使用惰性參數調用的函數本身表現為惰性,僅在需要時才進行評估。因此,在嚴格要求之前,不會調用惰性參數(可能是昂貴的參數)進行評估。
Django的數據庫層提供了多種方法來幫助開發(fā)人員從其數據庫中獲得最佳性能。該數據庫優(yōu)化文檔匯聚鏈接到相關文件,并增加了各種技巧,大綱的步驟嘗試優(yōu)化數據庫使用情況時服用。
啟用持久連接可以在大部分請求處理時間中加快與數據庫帳戶的連接。
例如,這對網絡性能有限的虛擬主機有很大幫助。
Django隨附了一些有用的中間件 ,可以幫助您優(yōu)化網站的性能。它們包括:
添加了對現代瀏覽器的支持,以基于ETag和Last-Modified標頭有條件地獲取響應 。如果需要,它還會計算并設置一個ETag。
壓縮所有現代瀏覽器的響應,節(jié)省帶寬和傳輸時間。請注意,當前將GZipMiddleware視為安全風險,并且容易受到使TLS / SSL提供的保護無效的攻擊的攻擊。有關GZipMiddleware更多信息,請參閱警告。
使用緩存的會話可能是一種通過避免從較慢的存儲源(如數據庫)中加載會話數據,而將頻繁使用的會話數據存儲在內存中來提高性能的方法。
靜態(tài)文件(根據定義不是動態(tài)的)是實現優(yōu)化收益的絕佳目標。
通過利用Web瀏覽器的緩存功能,您可以在初始下載后完全消除給定文件的網絡命中。
ManifestStaticFilesStorage在靜態(tài)文件的文件名后附加一個與內容相關的標記,以使瀏覽器可以安全地長期緩存它們,而不會丟失將來的更改-文件更改時,標記也將更改,因此瀏覽器將自動重新加載資產。
幾個第三方Django工具和軟件包提供了“最小化” HTML,CSS和JavaScript的功能。它們刪除了不必要的空格,換行符和注釋,并縮短了變量名,從而減小了站點發(fā)布的文檔的大小。
注意:
啟用通??梢源蟠筇岣咝阅?,因為它避免了每次需要渲染每個模板時就對每個模板進行編譯。cached template loader
有時值得檢查您所使用軟件的不同版本和性能更好的版本。
這些技術面向希望突破已經充分優(yōu)化的Django站點的性能極限的更高級的用戶。
但是,它們并不是解決性能問題的靈丹妙藥,它們不可能為尚未以正確方式做更多基本工作的網站帶來比邊緣收益更好的收益。
注意
值得重復一遍:尋找已經使用的軟件的替代品永遠不是解決性能問題的第一個答案。當達到此優(yōu)化級別時,您需要一個正式的基準測試解決方案。
新發(fā)行的維護良好的軟件效率較低的情況相當少見,但是維護人員無法預見所有可能的用例-因此,盡管意識到較新版本的性能可能會更好,但不要以為它們總是將。
Django本身就是這樣。后續(xù)版本在整個系統(tǒng)上提供了許多改進,但是您仍然應該檢查應用程序的實際性能,因為在某些情況下,您可能會發(fā)現更改意味著性能較差而不是更好。
較新版本的Python以及Python包也通常會表現更好-但要衡量而不是假設。
注意
除非您在特定版本中遇到不尋常的性能問題,否則通常會在新版本中找到更好的功能,可靠性和安全性,并且這些好處遠比您可能會贏得或失去的任何性能都重要。
在幾乎所有情況下,Django的內置模板語言都足夠了。但是,如果Django項目中的瓶頸似乎在模板系統(tǒng)中,而您又花了其他機會來解決此問題,那么第三方替代方法可能是答案。
Jinja2可以提高性能,特別是在速度方面。
替代模板系統(tǒng)在共享Django模板語言的程度上有所不同。
注意:如果您在模板中遇到性能問題,則要做的第一件事就是確切地了解原因。使用備用模板系統(tǒng)可能會證明更快,但是在不造成麻煩的情況下也可以獲得相同的收益-例如,可以在視圖中更有效地完成模板中的昂貴處理和邏輯。
可能值得檢查您所使用的Python軟件是否已以不同的實現提供,該實現可以更快地執(zhí)行相同的代碼。
但是:在編寫良好的Django站點中,大多數性能問題不是在Python執(zhí)行級別上,而是在效率低下的數據庫查詢,緩存和模板方面。如果您依賴編寫不佳的Python代碼,則無法通過更快地執(zhí)行來解決性能問題。
使用替代實現可能會引入兼容性,部署,可移植性或維護問題。不用說,在采用非標準實現之前,您應確保它為您的應用程序提供了足夠的性能提升,從而勝過了潛在的風險。
考慮到這些警告,您應該意識到:
PyPy是Python本身的Python實現(“標準” Python實現在C中)。PyPy通??捎糜谥亓考墤贸绦?,因此可顯著提高性能。
PyPy項目的主要目標是與現有的Python API和庫兼容。Django是兼容的,但您需要檢查您依賴的其他庫的兼容性。
一些Python庫也用C實現,并且速度可能更快。他們旨在提供相同的API。請注意,兼容性問題和行為差異并不是未知的(并且并不總是立即可見)。
詳情參考: https://docs.djangoproject.com/en/3.0/
更多建議: