亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python實現(xiàn)緩存的兩個簡單方法

 更新時間:2024年11月17日 09:04:31   作者:python收藏家  
緩存是一種用于提高應(yīng)用程序性能的技術(shù),它通過臨時存儲程序獲得的結(jié)果,以便在以后需要時重用它們,本文將學(xué)習(xí)Python中的不同緩存技術(shù),感興趣的可以了解下

緩存是一種用于提高應(yīng)用程序性能的技術(shù),它通過臨時存儲程序獲得的結(jié)果,以便在以后需要時重用它們。

在本文中,我們將學(xué)習(xí)Python中的不同緩存技術(shù),包括functools模塊中的@ lru_cache和@ cache裝飾器。

簡單示例:Python緩存實現(xiàn)

要在Python中創(chuàng)建緩存,我們可以使用functools模塊中的@cache裝飾器。在下面的代碼中,注意print()函數(shù)只執(zhí)行一次:

import functools

@functools.cache
def square(n):
    print(f"Calculating square of {n}")
    return n * n

# Testing the cached function
print(square(4))  # Output: Calculating square of 4 \n 16
print(square(4))  # Output: 16 (cached result, no recalculation)

輸出

Calculating square of 4
16
16

Python中的緩存是什么

假設(shè)我們需要解決一個數(shù)學(xué)問題,花一個小時得到正確的答案。如果第二天我們必須解決同樣的問題,那么重用我們以前的工作而不是從頭開始會很有幫助。

Python中的緩存遵循類似的原則–它在函數(shù)調(diào)用中計算值時存儲這些值,以便在再次需要時重用它們。這種類型的緩存也稱為記憶化。

讓我們看一個簡短的例子,它計算了兩次大范圍的數(shù)字之和:

output = sum(range(100_000_001))
print(output)
output = sum(range(100_000_001))
print(output)

輸出

5000000050000000
5000000050000000

計算兩次運行時間:

import timeit

print(
    timeit.timeit(
        "sum(range(100_000_001))",
        globals=globals(),
        number=1,
    )
)

print(
    timeit.timeit(
        "sum(range(100_000_001))",
        globals=globals(),
        number=1,
    )
)

輸出

1.2157779589979327
1.1848394999979064

輸出顯示,兩個調(diào)用所花費的時間大致相同(取決于我們的設(shè)置,我們可能會獲得更快或更慢的執(zhí)行時間)。

但是,我們可以使用緩存來避免多次計算相同的值。我們可以使用內(nèi)置functools模塊重新定義:

import functools
import timeit

sum = functools.cache(sum)

print(
    timeit.timeit(
        "sum(range(100_000_001))",
        globals=globals(),
        number=1,
    )
)

print(
    timeit.timeit(
        "sum(range(100_000_001))",
        globals=globals(),
        number=1,
    )
)

輸出

1.2760689580027247
2.3330067051574588e-06

第二個調(diào)用現(xiàn)在需要幾微秒的時間,而不是一秒鐘,因為從0到100,000,000的數(shù)字之和的結(jié)果已經(jīng)計算并緩存了-第二個調(diào)用使用之前計算和存儲的值。

functools.cache()裝飾器是在Python 3.9版本中添加的,但我們可以在舊版本中使用functools.lru_cache()。

Python緩存:不同的方法

Python的functools模塊有兩個裝飾器用于將緩存應(yīng)用于函數(shù)。讓我們通過一個示例來探索functools.lru_cache()和functools.cache()。

讓我們編寫一個函數(shù)sum_digits(),它接受一個數(shù)字序列并返回這些數(shù)字的位數(shù)之和。例如,如果我們使用元組(23,43,8)作為輸入,那么:

  • 23的數(shù)字之和是5
  • 43的數(shù)字之和是7
  • 8的數(shù)字之和是8
  • 因此,總和為20。

這是我們可以編寫sum_digits函數(shù)的一種方式:

def sum_digits(numbers):
    return sum(
        int(digit) for number in numbers for digit in str(number)
    )

numbers = 23, 43, 8

print(sum_digits(numbers))

輸出

20

讓我們使用這個函數(shù)來探索創(chuàng)建緩存的不同方法。

Python手動緩存

讓我們首先手動創(chuàng)建該高速緩存。雖然我們也可以很容易地自動化,但手動創(chuàng)建緩存有助于我們理解這個過程。

讓我們創(chuàng)建一個字典,并在每次使用新值調(diào)用函數(shù)時添加鍵值對來存儲結(jié)果。如果我們用一個已經(jīng)存儲在這個字典中的值調(diào)用函數(shù),函數(shù)將返回存儲的值,而不會再次計算:

import random
import timeit

def sum_digits(numbers):
    if numbers not in sum_digits.my_cache:
        sum_digits.my_cache[numbers] = sum(
            int(digit) for number in numbers for digit in str(number)
        )
    return sum_digits.my_cache[numbers]
sum_digits.my_cache = {}

numbers = tuple(random.randint(1, 1000) for _ in range(1_000_000))

print(
    timeit.timeit(
        "sum_digits(numbers)",
        globals=globals(),
        number=1
    )
)

print(
    timeit.timeit(
        "sum_digits(numbers)",
        globals=globals(),
        number=1
    )
)

輸出

0.28875587500078836
0.0044607500021811575

第二次調(diào)用sum_digits(numbers)比第一次調(diào)用快得多,因為它使用了緩存的值。

現(xiàn)在讓我們更詳細地解釋上面的代碼。首先,請注意,我們在定義函數(shù)后創(chuàng)建了字典sum_digits.my_cache,即使我們在函數(shù)定義中使用了它。

函數(shù)的作用是:檢查傳遞給函數(shù)的參數(shù)是否已經(jīng)是sum_digits.my_cache字典中的鍵之一。僅當(dāng)參數(shù)不在該高速緩存中時,才計算所有數(shù)字的和。

由于我們在調(diào)用函數(shù)時使用的參數(shù)作為字典中的鍵,因此它必須是可散列數(shù)據(jù)類型。列表是不可散列的,所以我們不能將它用作字典中的鍵。例如,讓我們嘗試用列表而不是元組來替換數(shù)字-這將引發(fā)TypeError:

# ...

numbers = [random.randint(1, 1000) for _ in range(1_000_000)]

# ...

輸出

Traceback (most recent call last):
...
TypeError: unhashable type: 'list'

手動創(chuàng)建緩存非常適合學(xué)習(xí),但現(xiàn)在讓我們探索更快的方法。

使用functools.lru_cache()進行Python緩存

Python從3.2版開始就有了lru_cache()裝飾器。函數(shù)名開頭的“lru”代表“least recently used”。我們可以把緩存看作是一個用來存儲經(jīng)常使用的東西的盒子–當(dāng)它填滿時,LRU策略會扔掉我們很長時間沒有使用過的東西,為新的東西騰出空間。

讓我們用@functools.lru_cache來裝飾sum_digits函數(shù):

import functools
import random
import timeit

@functools.lru_cache
def sum_digits(numbers):
    return sum(
        int(digit) for number in numbers for digit in str(number)
    )

numbers = tuple(random.randint(1, 1000) for _ in range(1_000_000))

print(
    timeit.timeit(
        "sum_digits(numbers)",
        globals=globals(),
        number=1
    )
)

print(
    timeit.timeit(
        "sum_digits(numbers)",
        globals=globals(),
        number=1
    )
)

輸出

0.28326129099878017
0.002184917000704445

多虧了緩存,第二個調(diào)用的運行時間大大縮短。

默認(rèn)情況下,該高速緩存存儲計算的前128個值。一旦所有128個位置都滿了,算法就會刪除最近最少使用的(LRU)值,為新值騰出空間。

當(dāng)我們使用maxsize參數(shù)修飾函數(shù)時,我們可以設(shè)置不同的最大緩存大?。?/p>

import functools
import random
import timeit

@functools.lru_cache(maxsize=5)
def sum_digits(numbers):
    return sum(
        int(digit) for number in numbers for digit in str(number)
    )

# ...

在這種情況下,該高速緩存僅存儲5個值。如果我們不想限制該高速緩存的大小,也可以將maxsize參數(shù)設(shè)置為None。

使用functools.cache()進行Python緩存

Python 3.9包含了一個更簡單、更快速的緩存裝飾器——functools. cache()。這個裝飾器有兩個主要特點:

  • 它沒有最大大小-這類似于調(diào)用functools.lru_cache(maxsize=None)。
  • 它存儲所有函數(shù)調(diào)用及其結(jié)果(它不使用LRU策略)。這適用于輸出相對較小的函數(shù),或者當(dāng)我們不需要擔(dān)心緩存大小限制時。

讓我們在sum_digits函數(shù)上使用@functools.cache裝飾器:

import functools
import random
import timeit

@functools.cache
def sum_digits(numbers):
    return sum(
        int(digit) for number in numbers for digit in str(number)
    )

numbers = tuple(random.randint(1, 1000) for _ in range(1_000_000))

print(
    timeit.timeit(
        "sum_digits(numbers)",
        globals=globals(),
        number=1
    )
)

print(
    timeit.timeit(
        "sum_digits(numbers)",
        globals=globals(),
        number=1
    )
)

輸出

0.16661812500024098
0.0018135829996026587

使用@functools.cache修飾sum_digits()等效于將sum_digits賦值給functools.cache():

# ...

def sum_digits(numbers):
    return sum(
        int(digit) for number in numbers for digit in str(number)
    )

sum_digits = functools.cache(sum_digits)

請注意,我們也可以使用不同的導(dǎo)入方式:

from functools import cache

這樣,我們就可以只使用@cache來裝飾我們的函數(shù)。

其他緩存策略

Python自己的工具實現(xiàn)了LRU緩存策略,刪除最近最少使用的條目,為新值騰出空間。

讓我們來看看其他一些緩存策略:

  • 先進先出(FIFO):當(dāng)該高速緩存已滿時,刪除添加的第一個項,為新值騰出空間。LRU和FIFO之間的區(qū)別在于,LRU將最近使用的項保存在該高速緩存中,而FIFO丟棄最舊的項而不管是否使用。
  • 后進先出(LIFO):當(dāng)該高速緩存已滿時,刪除最近添加的項。想象一下自助餐廳里的一堆盤子。我們最近放入堆棧的盤子(最后一個)是我們將首先取出的盤子(第一個)。
  • Most-recently used(MRU):當(dāng)該高速緩存中需要空間時,將丟棄最近使用的值。
  • 隨機替換(RR):該策略隨機丟棄一個項目,為新項目騰出空間。

這些策略還可以與有效生存期的度量相結(jié)合,有效生存期指的是該高速緩存中的一段數(shù)據(jù)被認(rèn)為有效或相關(guān)的時間。想象一下緩存中的一篇新聞文章。它可能經(jīng)常被訪問(LRU會保留它),但一周后,新聞可能會過時。

Python中緩存時的常見挑戰(zhàn)

我們已經(jīng)了解了Python中緩存的優(yōu)點。在實現(xiàn)緩存時,還需要記住一些挑戰(zhàn)和缺點:

  • 緩存失效和一致性:數(shù)據(jù)可能會隨著時間而變化。因此,存儲在緩存中的值也可能需要更新或刪除。
  • 內(nèi)存管理:在緩存中存儲大量數(shù)據(jù)需要內(nèi)存,如果緩存無限增長,這可能會導(dǎo)致性能問題。
  • 復(fù)雜性:添加緩存會在創(chuàng)建和維護該高速緩存時給系統(tǒng)帶來復(fù)雜性。通常,好處大于這些成本,但這種增加的復(fù)雜性可能會導(dǎo)致難以發(fā)現(xiàn)和糾正的錯誤。

結(jié)論

當(dāng)對同一數(shù)據(jù)重復(fù)執(zhí)行計算密集型操作時,我們可以使用緩存來優(yōu)化性能。

Python有兩個裝飾器在調(diào)用函數(shù)時創(chuàng)建緩存:functools模塊中的@lru_cache和@cache。

但是,我們需要確保該高速緩存保持最新,并正確管理內(nèi)存。

到此這篇關(guān)于Python實現(xiàn)緩存的兩個簡單方法的文章就介紹到這了,更多相關(guān)Python緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python 實現(xiàn)檢驗33品種數(shù)據(jù)是否是正態(tài)分布

    python 實現(xiàn)檢驗33品種數(shù)據(jù)是否是正態(tài)分布

    今天小編就為大家分享一篇python 實現(xiàn)檢驗33品種數(shù)據(jù)是否是正態(tài)分布,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Python利用命名空間解析XML文檔

    Python利用命名空間解析XML文檔

    這篇文章主要介紹了Python利用命名空間解析XML文檔,幫助大家更好的理解和學(xué)習(xí)Python,感興趣的朋友可以了解下
    2020-08-08
  • python和websocket構(gòu)建實時日志跟蹤器的步驟

    python和websocket構(gòu)建實時日志跟蹤器的步驟

    這篇文章主要介紹了python和websocket構(gòu)建實時日志跟蹤器的步驟,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下
    2021-04-04
  • Python控制臺輸出時刷新當(dāng)前行內(nèi)容而不是輸出新行的實現(xiàn)

    Python控制臺輸出時刷新當(dāng)前行內(nèi)容而不是輸出新行的實現(xiàn)

    今天小編就為大家分享一篇Python控制臺輸出時刷新當(dāng)前行內(nèi)容而不是輸出新行的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • python opencv檢測直線 cv2.HoughLinesP的實現(xiàn)

    python opencv檢測直線 cv2.HoughLinesP的實現(xiàn)

    cv2.HoughLines()函數(shù)是在二值圖像中查找直線,本文結(jié)合示例詳細的介紹了cv2.HoughLinesP的用法,感興趣的可以了解一下
    2021-06-06
  • python中最小二乘法詳細講解

    python中最小二乘法詳細講解

    在本篇文章里小編給大家整理的是一篇關(guān)于python中最小二乘法詳細講解內(nèi)容,需要的朋友們可以參考下。
    2021-02-02
  • Python中子類繼承父類傳遞參數(shù)的方法

    Python中子類繼承父類傳遞參數(shù)的方法

    在面向?qū)ο缶幊讨?繼承是一種使得一個類(稱為子類)能夠獲取另一個類(稱為父類)的屬性和方法的機制,Python支持繼承,并提供了靈活的方式來繼承和擴展類的功能,本文將詳細介紹如何在Python中使用子類繼承父類,并傳遞參數(shù),需要的朋友可以參考下
    2025-03-03
  • Selenium自動化測試實現(xiàn)窗口切換

    Selenium自動化測試實現(xiàn)窗口切換

    這篇文章主要介紹了Selenium自動化測試實現(xiàn)窗口切換,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • python?pygame英雄循環(huán)飛行及作業(yè)示例

    python?pygame英雄循環(huán)飛行及作業(yè)示例

    這篇文章主要為大家介紹了python?pygame英雄循環(huán)飛行及作業(yè)實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Python入門教程之三元運算符的使用詳解

    Python入門教程之三元運算符的使用詳解

    三元運算符也稱為條件表達式,是根據(jù)條件為真或假來評估某些內(nèi)容的運算符。它在2.5 版本中被添加到 Python 中。 本文將通過示例詳細說說三元運算符的使用,需要的可以參考一下
    2022-09-09

最新評論