在程式開發中,當我們面對一些重複計算或耗時操作時,經常希望能夠將已經計算過的結果暫存起來,以避免重複計算,從而提升程式效能。
在 Python 中,functools 模組提供了一個簡單而強大的裝飾器 —— @lru_cache,可以輕鬆實現這樣的快取 (Cache) 功能。
LRU 是 Least Recently Used (最近最少使用) 的縮寫,lru_cache 是一個基於 LRU 策略的快取工具。
它可以自動記住函數的調用結果,當傳入相同參數時,直接返回快取結果,而不需要再次計算。這對於一些需要頻繁調用的計算函數 (如遞迴、數學運算、資料請求等) 特別有用。
本篇文章將從基礎概念開始,詳細介紹 lru_cache 的使用方法、參數設定、應用場景,並通過實例幫助你理解如何有效利用這個工具提升程式效能。
什麼是 LRU 快取?
LRU (Least Recently Used) 是一種常見的快取置換策略,適用於有限的快取空間中。
它的核心邏輯是:
- 當快取空間滿時,會優先移除「最近最少使用」的資料,以空出位置給新的資料。
- 這樣可以保證經常被使用的資料能夠留在快取中,而不常用的資料則會被淘汰。
舉例說明:
假設一個 LRU 快取最多可以存 3 條數據:
- 依次加入
A, B, C,快取中為[A, B, C]。 - 再加入
D,空間不夠,因此淘汰最久未使用的A,得到[B, C, D]。 - 此時訪問了
B,B成為最新使用的資料,快取變成[C, D, B]。 - 再加入
E,則會移除C,變為[D, B, E]。
常見應用場景
- 遞迴運算: 如費式數列、數學計算等。
- 重複的資料查詢: 如 API 請求、資料庫查詢。
- 耗時計算: 如影像處理、數據分析。
- 減少不變數據的重複計算: 如靜態配置、初始化設置。
如何使用 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 時的注意事項
- 僅適用於「可雜湊」的參數: 例如數字、字串、元組 (不可變類型)。
- 對於大型資料快取要謹慎: 可能導致記憶體消耗過多。
- 多線程 (Thread) 中的使用:
lru_cache是執行緒安全 (Thread-safe) 的,不過在複雜情境下仍需謹慎。 - 手動清除快取: 在資料來源變動後,及時清除快取,避免過期資料被使用。
查看、清除快取
當需要清空快取時
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 是優化程式效能的一個得力工具!