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