av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

您的位置:首頁技術(shù)文章
文章詳情頁

Django程序的優(yōu)化技巧

瀏覽:8日期:2024-09-08 17:56:33
友情提示:

過度性能優(yōu)化是沒有必要甚至有害的,因為花大力氣帶來的毫秒級的響應(yīng)提升你的用戶可能根本感知不到,畢竟開發(fā)人員的時間也很寶貴。

性能優(yōu)化指標(biāo)

在對一個Web項目進(jìn)行性能優(yōu)化時,我們通常需要評價多個指標(biāo):

響應(yīng)時間 最大并發(fā)連接數(shù) 代碼的行數(shù) 函數(shù)調(diào)用次數(shù) 內(nèi)存占用情況 CPU占比

其中響應(yīng)時間(服務(wù)器從接收用戶請求,處理該請求并返回結(jié)果所需的總的時間)通常是最重要的指標(biāo),因為過長的響應(yīng)時間會讓用戶厭倦等待,轉(zhuǎn)投其它網(wǎng)站或APP。當(dāng)你的用戶數(shù)量變得非常龐大,如何提高最大并發(fā)連接數(shù),減少內(nèi)存消耗也將變得非常重要。

在開發(fā)環(huán)境中,我們一般建議使用django-debug-toolbar和django-silk來進(jìn)行性能監(jiān)測分析。它們提供了每次用戶請求的響應(yīng)時間,并告訴你程序執(zhí)行過程哪個環(huán)節(jié)(比如SQL查詢)最消耗時間。

對于中大型網(wǎng)站或Web APP而言,最影響網(wǎng)站性能的就是數(shù)據(jù)庫查詢部分了。一是反復(fù)從數(shù)據(jù)庫讀寫數(shù)據(jù)很消耗時間和計算資源,二是當(dāng)返回的查詢數(shù)據(jù)集queryset非常大時還會占據(jù)很多內(nèi)存。我們先從這部分優(yōu)化做起。

數(shù)據(jù)庫查詢優(yōu)化利用Queryset的惰性和緩存,避免重復(fù)查詢

充分利用Django的QuerySet的惰性和自帶緩存特性,可以幫助我們減少數(shù)據(jù)庫查詢次數(shù)。比如下例中例1比例2要好。因為在你打印文章標(biāo)題后,Django不僅執(zhí)行了數(shù)據(jù)庫查詢,還把查詢到的article_list放在了緩存里,下次可以在其它地方復(fù)用,而例2就不行了。

# 例1: 利用了緩存特性 - Good article_list = Article.objects.filter(title__contains='django') for article in article_list: print(article.title) # 例2: Bad for article in Article.objects.filter(title__contains='django'): print(article.title)

但有時我們只希望了解查詢的結(jié)果是否存在或查詢結(jié)果的數(shù)量,這時可以使用exists()和count()方法,如下所示。這樣就不會浪費資源查詢一個用不到的數(shù)據(jù)集,還可以節(jié)省內(nèi)存。

# 例3: Good article_list = Article.objects.filter(title__contains='django') if article_list.exists(): print('Records found.') else: print('No records') # 例4: Good count = Article.objects.filter(title__contains='django').count()一次查詢所有需要的關(guān)聯(lián)模型數(shù)據(jù)

假設(shè)我們有一個文章(Article)模型,其與類別(Category)是單對多的關(guān)系(ForeignKey), 與標(biāo)簽(Tag)是多對多的關(guān)系(ManyToMany)。我們需要編寫一個article_list的函數(shù)視圖,以列表形式顯示文章清單及每篇文章的類別和標(biāo)簽,你的模板文件可能如下所示:

{% for article in articles %} <li>{{ article.title }} </li> <li>{{ article.category.name }}</li> <li>{% for tag in article.tags.all %} {{ tag.name }},{% endfor %} </li> {% endfor %}

在模板里每進(jìn)行一次for循環(huán)獲取關(guān)聯(lián)對象category和tag的信息,Django就要單獨進(jìn)行一次數(shù)據(jù)庫查詢,造成了極大資源浪費。我們完全可以使用select_related方法和prefetch_related方法一次性從數(shù)據(jù)庫獲取單對多和多對多關(guān)聯(lián)模型數(shù)據(jù),這樣在模板中遍歷時Django也不會執(zhí)行數(shù)據(jù)庫查詢了。

# 僅獲取文章數(shù)據(jù) - Bad def article_list(request): articles = Article.objects.all() return render(request, ’blog/article_list.html’,{’articles’: articles, }) # 一次性提取關(guān)聯(lián)模型數(shù)據(jù) - Good def article_list(request): articles = Article.objects.all().select_related(’category’).prefecth_related(’tags’) return render(request, ’blog/article_list.html’, {’articles’: articles, })僅查詢需要用到的數(shù)據(jù)

默認(rèn)情況下Django會從數(shù)據(jù)庫中提取所有字段,但是當(dāng)數(shù)據(jù)表有很多列很多行的時候,告訴Django提取哪些特定的字段就非常有意義了。假如我們數(shù)據(jù)庫中有100萬篇文章,需要循環(huán)打印每篇文章的標(biāo)題。如果按例4操作,我們會將每篇文章對象的全部信息都提取出來載入到內(nèi)存中,不僅花費更多時間查詢,還會大量占用內(nèi)存,而最后只用了title這一個字段,這是完全沒有必要的。我們完全可以使用values和value_list方法按需提取數(shù)據(jù),比如只獲取文章的id和title,節(jié)省查詢時間和內(nèi)存(例6-例8)。

# 例子5: Bad article_list = Article.objects.all() if article_list: print(article.title) # 例子6: Good - 字典格式數(shù)據(jù) article_list = Article.objects.values(’id’, ’title’) if article_list: print(article.title) # 例子7: Good - 元組格式數(shù)據(jù) article_list = Article.objects.values_list(’id’, ’title’) if article_list: print(article.title) # 例子8: Good - 列表格式數(shù)據(jù) article_list = Article.objects.values_list(’id’, ’title’, flat=True) if article_list: print(article.title)

除此以外,Django項目還可以使用defer和only這兩個查詢方法來實現(xiàn)這一點。第一個用于指定哪些字段不要加載,第二個用于指定只加載哪些字段。

使用分頁,限制最大頁數(shù)

事實前面代碼可以進(jìn)一步優(yōu)化,比如使用分頁僅展示用戶所需要的數(shù)據(jù),而不是一下子查詢所有數(shù)據(jù)。同時使用分頁時也最好控制最大頁數(shù)。比如當(dāng)你的數(shù)據(jù)庫有100萬篇文章時,每頁即使展示100篇,也需要1萬頁展示給你的用戶,這是完全沒有必要的。你可以完全只展示前200頁的數(shù)據(jù),如下所示:

LIMIT = 100 * 200 data = Articles.objects.all()[:(LIMIT + 1)] if len(data) > LIMIT: raise ExceededLimit(LIMIT) return data數(shù)據(jù)庫設(shè)置優(yōu)化

如果你使用單個數(shù)據(jù)庫,你可以采用如下手段進(jìn)行優(yōu)化:

建立模型時能用CharField確定長度的字段盡量不用不用TextField, 可節(jié)省存儲空間; 可以給搜索頻率高的字段屬性,在定義模型時使用索引(db_index=True); 持久化數(shù)據(jù)庫連接。

沒有持久化連接,Django每個請求都會與數(shù)據(jù)庫創(chuàng)建一個連接,直到請求結(jié)束,關(guān)閉連接。如果數(shù)據(jù)庫不在本地,每次建立和關(guān)閉連接也需要花費一些時間。設(shè)置持久化連接時間,僅需要添加CONN_MAX_AGE參數(shù)到你的數(shù)據(jù)庫設(shè)置中,如下所示:

DATABASES = { ‘default’: { ‘ENGINE’: ‘django.db.backends.postgresql_psycopg2’, ‘NAME’: ‘postgres’, ‘CONN_MAX_AGE’: 60, # 60秒 } }

當(dāng)然CONN_MAX_AGE也不宜設(shè)置過大,因為每個數(shù)據(jù)庫并發(fā)連接數(shù)有上限的(比如mysql默認(rèn)的最大并發(fā)連接數(shù)是100個)。如果CONN_MAX_AGE設(shè)置過大,會導(dǎo)致mysql 數(shù)據(jù)庫連接數(shù)飆升很快達(dá)到上限。當(dāng)并發(fā)請求數(shù)量很高時,CONN_MAX_AGE應(yīng)該設(shè)低點,比如30s, 10s或5s。當(dāng)并發(fā)請求數(shù)不高時,這個值可以設(shè)得長一點,比如60s或5分鐘。

當(dāng)你的用戶非常多、數(shù)據(jù)量非常大時,你可以考慮讀寫分離、主從復(fù)制、分表分庫的多數(shù)據(jù)庫服務(wù)器架構(gòu)。這種架構(gòu)上的布局是對所有web開發(fā)語言適用的,并不僅僅局限于Django,這里不做進(jìn)一步展開了。

緩存

緩存是一類可以更快的讀取數(shù)據(jù)的介質(zhì)統(tǒng)稱,也指其它可以加快數(shù)據(jù)讀取的存儲方式。一般用來存儲臨時數(shù)據(jù),常用介質(zhì)的是讀取速度很快的內(nèi)存。一般來說從數(shù)據(jù)庫多次把所需要的數(shù)據(jù)提取出來,要比從內(nèi)存或者硬盤等一次讀出來付出的成本大很多。對于中大型網(wǎng)站而言,使用緩存減少對數(shù)據(jù)庫的訪問次數(shù)是提升網(wǎng)站性能的關(guān)鍵之一。

視圖緩存

from django.views.decorators.cache import cache_page @cache_page(60 * 15) def my_view(request): ...使用@cached_property裝飾器緩存計算屬性

對于不經(jīng)常變動的計算屬性,可以使用@cached_property裝飾器緩存結(jié)果。

緩存臨時性數(shù)據(jù)比如sessions

Django的sessions默認(rèn)是存在數(shù)據(jù)庫中的,這樣的話每一個請求Django都要使用sql查詢會話數(shù)據(jù),然后獲得用戶對象的信息。對于臨時性的數(shù)據(jù)比如sessions和messages,最好將它們放到緩存里,也可以減少SQL查詢次數(shù)。

SESSION_ENGINE = ’django.contrib.sessions.backends.cache’

模版緩存

默認(rèn)情況下Django每處理一個請求都會使用模版加載器都會去文件系統(tǒng)搜索模板,然后渲染這些模版。你可以通過使用cached.Loader開啟模板緩存加載。這時Django只會查找并且解析你的模版一次,可以大大提升模板渲染效率。

TEMPLATES = [{ ’BACKEND’: ’django.template.backends.django.DjangoTemplates’, ’DIRS’: [BASE_DIR / ’templates’], ’OPTIONS’: { ’loaders’: [ (’django.template.loaders.cached.Loader’, [ ’django.template.loaders.filesystem.Loader’, ’django.template.loaders.app_directories.Loader’, ’path.to.custom.Loader’, ]),], }, }]

注意:不建議在開發(fā)環(huán)境中(Debug=True)時開啟緩存加載,因為修改模板后你不能及時看到修改后的效果。

另外模板文件中建議使用with標(biāo)簽緩存視圖傳來的數(shù)據(jù),便于下一次時使用。對于公用的html片段,也建議使用緩存。

{% load cache %} {% cache 500 sidebar request.user.username %} .. sidebar for logged in user .. {% endcache %}靜態(tài)文件

壓縮 HTML、CSS 和 JavaScript等靜態(tài)文件可以節(jié)省帶寬和傳輸時間。Django 自帶的壓縮工具有GzipMiddleware 中間件和 spaceless 模板 Tag。使用Python壓縮靜態(tài)文件會影響性能,一個更好的方法是通過 Apache、Nginx 等服務(wù)器來對輸出內(nèi)容進(jìn)行壓縮。例如Nginx服務(wù)器支持gzip壓縮,同時可以通過expires選項設(shè)置靜態(tài)文件的緩存時間。

以上就是Django程序的優(yōu)化技巧的詳細(xì)內(nèi)容,更多關(guān)于Django程序的優(yōu)化的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Django
相關(guān)文章:
主站蜘蛛池模板: 综合一区二区三区 | 狠狠干av | 国产精品美女在线观看 | 久久综合久 | 操操日| 日本视频免费观看 | 一区二区三区高清在线观看 | 亚洲www | 一级大片网站 | 国户精品久久久久久久久久久不卡 | 激情欧美一区二区三区中文字幕 | 亚洲成人免费av | 亚洲视频在线一区 | 黄色一级大片在线免费看产 | 久久性av | 天天操夜夜操免费视频 | 中文字幕一区在线 | 91在线视频一区 | 日韩中文字幕在线不卡 | 国产第二页 | 欧美一级片在线观看 | 毛片一级片 | 性网站免费 | 日韩1区2区 | 草久久 | 国产午夜精品视频 | 在线欧美视频 | 91在线免费观看网站 | 国产99久久久国产精品 | 一级片子 | 欧美一区免费 | 日韩精品在线播放 | 日本视频在线播放 | 伊人精品在线 | 欧美性生交大片免费 | 久久久国产一区 | 五月综合激情网 | 欧美在线视频观看 | 久久亚洲一区二区三 | 免费国产视频 | 精品伦精品一区二区三区视频 |