初學者指南:深入了解 Python 的 lru_cache 快取機制

Published March 10, 2025 by 徐培鈞
Python

在程式開發中,當我們面對一些重複計算耗時操作時,經常希望能夠將已經計算過的結果暫存起來,以避免重複計算,從而提升程式效能。

在 Python 中,functools 模組提供了一個簡單而強大的裝飾器 —— @lru_cache,可以輕鬆實現這樣的快取 (Cache) 功能。

LRULeast Recently Used (最近最少使用) 的縮寫,lru_cache 是一個基於 LRU 策略的快取工具。

它可以自動記住函數的調用結果,當傳入相同參數時,直接返回快取結果,而不需要再次計算。這對於一些需要頻繁調用的計算函數 (如遞迴、數學運算、資料請求等) 特別有用。

本篇文章將從基礎概念開始,詳細介紹 lru_cache 的使用方法、參數設定、應用場景,並通過實例幫助你理解如何有效利用這個工具提升程式效能。


什麼是 LRU 快取?

LRU (Least Recently Used) 是一種常見的快取置換策略,適用於有限的快取空間中。

它的核心邏輯是:

  • 當快取空間滿時,會優先移除「最近最少使用」的資料,以空出位置給新的資料。
  • 這樣可以保證經常被使用的資料能夠留在快取中,而不常用的資料則會被淘汰。

舉例說明

假設一個 LRU 快取最多可以存 3 條數據:

  1. 依次加入 A, B, C,快取中為 [A, B, C]
  2. 再加入 D,空間不夠,因此淘汰最久未使用的 A,得到 [B, C, D]
  3. 此時訪問了 BB 成為最新使用的資料,快取變成 [C, D, B]
  4. 再加入 E,則會移除 C,變為 [D, B, E]

常見應用場景

  1. 遞迴運算: 如費式數列、數學計算等。
  2. 重複的資料查詢: 如 API 請求、資料庫查詢。
  3. 耗時計算: 如影像處理、數據分析。
  4. 減少不變數據的重複計算: 如靜態配置、初始化設置。

如何使用 lru_cache 裝飾器

基本語法

from functools import lru_cache

@lru_cache(maxsize=128)
def slow_function(n):
    print(f"計算中: {n}")
    return n * n
  • @lru_cache 是一個裝飾器,會將函數的返回結果快取起來。
  • maxsize 是可選參數,用於設定最多快取多少條結果 (預設 128)。

基本示例

@lru_cache
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# 計算 Fibonacci(10)
print(fibonacci(10))  # 55

# 快取效果展示
print(fibonacci.cache_info())
  • 第一次計算 Fibonacci(10) 時,需要經過多次遞迴,但結果會快取起來。
  • 之後如果再調用 fibonacci(10),將直接返回快取結果,而不會重複計算。

設定快取大小 (maxsize 參數)

為什麼需要 maxsize

maxsize 決定了快取的最大儲存數量:

  • maxsize=None:表示無限快取 (可能會導致記憶體佔用過大)。
  • maxsize=0:禁用快取 (每次都重新計算)。
  • maxsize=正整數:設定快取的最大儲存數量,例如 @lru_cache(maxsize=100)

示例:限制快取大小

@lru_cache(maxsize=3)
def process_data(n):
    print(f"計算: {n}")
    return n * 2

process_data(1)
process_data(2)
process_data(3)
process_data(1)  # 這次調用會命中快取
process_data(4)  # 超出快取大小,會移除最早的 (2)

print(process_data.cache_info())  
# CacheInfo(hits=1, misses=4, maxsize=3, currsize=3)
  • hits:命中快取的次數。
  • misses:未命中快取,需要重新計算的次數。
  • maxsize:設定的最大快取大小。
  • currsize:當前快取中的項目數量。

使用 lru_cache 時的注意事項

  1. 僅適用於「可雜湊」的參數: 例如數字、字串、元組 (不可變類型)。
  2. 對於大型資料快取要謹慎: 可能導致記憶體消耗過多。
  3. 多線程 (Thread) 中的使用: lru_cache執行緒安全 (Thread-safe) 的,不過在複雜情境下仍需謹慎。
  4. 手動清除快取: 在資料來源變動後,及時清除快取,避免過期資料被使用。

查看、清除快取

當需要清空快取時

process_data.cache_clear()
print(process_data.cache_info())  
# CacheInfo(hits=0, misses=0, maxsize=3, currsize=0)
  • 當資料變動時,可能需要手動清除快取,以避免使用過期資料。

快取資訊方法

print(process_data.cache_info())
  • 可以方便地了解目前快取的使用情況,包括命中率 (hit/miss) 和空間使用情況。

結語

lru_cache 是 Python 中一個非常實用的工具,能夠輕鬆地提升程式的效率,特別是在重複計算或耗時操作中表現出色。

它的使用方式非常簡單,只需加上 @lru_cache 裝飾器,並根據情況設定快取大小,即可快速啟用快取功能。

對於初學者來說,建議從一些簡單的計算函數開始嘗試使用 lru_cache,觀察快取命中率 (cache_info) 和快取清除 (cache_clear) 的效果。

隨著經驗的積累,你會發現 lru_cache 是優化程式效能的一個得力工具!