
functools.cache กับ lru_cache: เมื่อไหร่ควรจำกัดขนาดแคช
น้องกายEngineering
เคยคำนวณค่าเดิมซ้ำในฟังก์ชันบริสุทธิ์ไหม ผมเคย จนหันมาใช้แคชใน functools
ตามเอกสาร functools มีสองตัวที่คนสับสนบ่อย:
@functools.cache— จำผลไม่จำกัดขนาด (เทียบเท่า@lru_cache(maxsize=None))@functools.lru_cache(maxsize=…)— จำผลแบบ LRU จำกัดจำนวนรายการ
เลือกยังไง
- อาร์กิวเมนต์ที่เป็นไปได้น้อยและคงที่ →
@cacheสั้นๆ ชัด - อาร์กิวเมนต์หลากหลายหรือมาจากอินพุตผู้ใช้ →
@lru_cache(maxsize=…)กันหน่วยความจำโตไม่รู้จบ - ฟังก์ชันต้องมีอาร์กิวเมนต์ hashable ทั้งคู่
from functools import cache, lru_cache
calls = {"cache": 0, "lru": 0}
@cache
def fib_cache(n):
calls["cache"] += 1
return n if n < 2 else fib_cache(n - 1) + fib_cache(n - 2)
@lru_cache(maxsize=4)
def fib_lru(n):
calls["lru"] += 1
return n if n < 2 else fib_lru(n - 1) + fib_lru(n - 2)
assert fib_cache(10) == 55
assert fib_lru(10) == 55
assert calls["cache"] == 11 # n=0..10 once each
info = fib_lru.cache_info()
assert info.maxsize == 4
assert info.hits + info.misses >= 1
print("ok", calls["cache"], info.hits, info.misses)
Recap
@cache= ไม่จำกัดขนาด ใช้เมื่อคีย์น้อย@lru_cache(maxsize=…)เมื่อกลัวหน่วยความจำโต- อาร์กิวเมนต์ต้อง hashable
- ดู
cache_info()ตอนไล่ประสิทธิภาพ