如何讓Python程式輕鬆加速,正確方法詳解

2022-05-16 09:41:06 字數 3168 閱讀 8116

你可能在想,這很好,但這個裝飾器究竟是什麼?它提供對已構建的快取的訪問,該快取使用lru(譯者注: least recently used的縮寫,即最近最少使用,是一種常用的頁面置換演算法,選擇最近最久未使用的頁面予以淘汰。)的置換策略,因此被命名為lru_cache。當然,這句話聽起來可能有點令人膽怯,所以讓我們把它分解一下。

什麼是快取?

快取是乙個可以快速訪問的地方,可以在它裡面儲存訪問速度較慢的內容。為了演示這一點,讓我們以你的web瀏覽器為例。

從網路上讀取網頁可能需要幾秒鐘,即使是快速的網路連線也如此。在計算機時代,這個問題是永恆的。為了解決這個問題,瀏覽器將你已經訪問過的網頁儲存在計算機的快取中,這樣訪問速度會加快數千倍。

檢查頁面的本地快取。如果頁面在那裡,返回該頁面。

將該網頁儲存在快取中,以便將來更快地訪問。

雖然快取並不會讓你第一次訪問網頁的速度加快,但通常你是要屢次訪問某乙個**頁面的(想想facebook——注:對多數國人來講,可能不是這個**,或者你的電子郵件),有了快取之後,以後每次訪問都會更快。

瀏覽器並不是唯一使用快取的,從伺服器到cpu和硬碟或ssd之間的計算機硬體,它們無處不在。從快取中可以很快地獲取資料,因此當你不止一次獲取資料時,它可以大大加快程式的速度。

快取只能儲存有限數量的東西,而且通常它比可能存入所快取的東西要小得多(例如,你的硬碟比網際網路小得多)。這意味著有時需要將快取中已有內容替換掉,放入其他內容。對於去掉什麼的決策方法被稱為置換策略。

這就是lru的用武之地。lru代表最近用得最少的快取中內容,這是一種常用的快取置換策略。

為什麼置換策略很重要?

在上圖中,快取中的每個項都附帶了訪問時間。依據lru策略,選擇訪問時間為2:55pm 的項作為要置換的項,因為它是最早被訪問的。如果有兩個物件具有相同的訪問時間,那麼lru將從中隨機選擇乙個。

這種去掉長時間不用的東西的策略,被稱為bélády的最優演算法,它是置換快取內容的最佳策略。當然,我們根本不知道未來會有什麼操作。謝天謝地,在許多情況下,lru提供了近乎最佳的效能。

functools.lru_cache是乙個裝飾器,因此你可以將它放在函式的頂部:

import functools

@functools.lru_cache(maxsize=128)

def fib(n):

if n < 2:

return 1

return fib(n-1) + fib(n-2)

複製**

fibonacci數列在遞迴示例中經常被用到,要提公升這個函式的速度,使用functools.lru_cache之後,不費吹灰之力,就能讓這個遞迴函式狂飆。在我的機器上執行這些**,得到了這個函式有快取版本和沒有快取版本的以下結果。

$ python3 -m timeit -s 'from fib_test import fib' 'fib(30)'

10 loops, best of 3: 282 msec per loop

$ python3 -m timeit -s 'from fib_test import fib_cache' 'fib_cache(30)'

10000000 loops, best of 3: 0.0791 usec per loop

複製**

增加一行**之後,速度提高了3565107倍。

當然,我認為很難看出你在實際中會如何使用它,因為我們很少需要計算斐波那契數列。回到web頁面示例,我們可以舉乙個更實際的用快取渲染前端模板的例子。

在伺服器開發中,通常單個頁面儲存為具有佔位符變數的模板。例如,下面是乙個頁面模板,該頁面顯示某一天各種足球比賽的結果。

"matches">

home team

away team

score

}}} - }

複製**

呈現模板時,看起來如下所示:

這是快取的主要目標,因為每天的結果不會改變,而且很可能每天會有多次訪問。下面是乙個提供此模板的flask應用程式。我引入了50ms的延遲來模擬通過網路或者從大型資料庫獲取匹配字典。

import json

import time

from flask import flask, render_template

with open('match.json','r') as f:

match_dict = json.load(f)

def get_matches(day):

# simulate network/database delay

time.sleep(0.05)

return match_dict[day]

def show_matches(day):

matches = get_matches(day)

return render_template('matches.html', matches=matches, day=day)

if __name__ == "__main__":

複製**

使用requests在不快取的情況下獲得三天的資料,在我的計算機上本地執行平均需要171ms。這還不錯,但我們可以做得更好,即使考慮到人為的延遲。

@functools.lru_cache(maxsize=4)

def show_matches(day):

matches = get_matches(day)

return render_template('matches.html', matches=matches, day=day)

複製**

在本例中,我設定了maxsize=4,因為我的測試指令碼只有相同的三天,最好設定2次冪。使用這種方法,10個迴圈的平均速度可以降到13.7ms。

python文件雖然很詳細,但是有一些東西還是要強調的。

裝飾器附帶了一些很有用的內建函式。cache_info()返回訪問數(hits)、未訪問數(misses)和當前快取使用量(currsize)、最大容量(maxsize),幫助你了解快取使用情況。cache_clear()將刪除快取中的所有元素。

通常,只有在以下情況下才能使用快取:

如何讓MySQL語句執行加速?

一開啟科技類論壇,最常看到的文章主題就是mysql效能優化了,為什麼要優化呢?因為 就是咱們說的 效能問題 程式設計師一遇到它總是焦頭爛額!今天對mysql優化總結了一些心得,希望在大家之後的工作中能有所有幫助!like模糊查詢形如 aaa 和 aaa 將不會使用索引,但是業務上不可避免可能又需要使...

使用numba加速python程式

前面說過使用cython來加速python程式的執行速度,但是相對來說程式改動較大,這次就說一種簡單的方式來加速python計算速度的方法,就是使用numba庫來進行,numba庫可以使用jit技術即時編譯,達到高效能,另外也可以使用cuda gpu的計算能力來加速,對python來說是乙個提速非常...

如何加速你的PHP程式

我一直認為php的執行速度是非常的理想的,尤其是zend引擎的加速之後。但是php仍然有加速的可能,你知道嗎?所有的一切都始於如何優化php的編譯 嘗試使用針對cpu型號的特殊編譯引數 msse mmmx mfpmath sse 在編譯的時候新增 03引數 編譯的時候調節cpu的引數 march m...