Tăng Tốc Code Bằng Caching Trong 1 Dòng Code
- Home
- Tăng Tốc Code Bằng Caching Trong 1 Dòng Code
rong phát triển phần mềm, tối ưu hiệu năng (Performance Optimization) luôn là bài toán đau đầu khi dữ liệu lớn hoặc hàm thực thi tốn nhiều tài nguyên. Thay vì viết lại logic caching phức tạp với Redis hay Memcached cho các tác vụ nội bộ trong tiến trình (in-memory), Python cung cấp sẵn functools.lru_cache.
Bài viết này DC Soft Tech sẽ cùng bạn bóc tách cơ chế và cách ứng dụng lru_cache thực chiến.
lru_cache là gì và cơ chế hoạt động?Khái niệm: lru_cache viết tắt của Least Recently Used Cache, là một decorator trong thư viện chuẩn functools của Python.
Cơ chế: Nó lưu trữ (memoization) kết quả trả về của hàm tương ứng với các đối số truyền vào. Khi hàm được gọi lại với cùng bộ đối số đó, Python trả về kết quả từ cache ngay lập tức thay vì chạy lại logic bên trong.
Chính sách LRU: Khi cache đầy (maxsize), phần tử ít được sử dụng trong thời gian gần đây nhất sẽ bị loại bỏ để nhường chỗ cho kết quả mới.
Hãy xét bài toán tính số Fibonacci kinh điển bằng đệ quy thuần túy:
import time
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
start = time.time()
print("Kết quả:", fibonacci(35))
print(f"Thời gian không cache: {time.time() - start:.4f}s")
Thời gian chạy với n=35 có thể mất hàng giây do tính lặp lại hàng triệu lần các nhánh con.
Áp dụng @lru_cache:
import time
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci_cached(n):
if n < 2:
return n
return fibonacci_cached(n - 1) + fibonacci_cached(n - 2)
start = time.time()
print("Kết quả:", fibonacci_cached(35))
print(f"Thời gian có cache: {time.time() - start:.6s}s")
Kết quả trả về gần như tức lập (0.0000xxs).
lru_cache cung cấp sẵn các method hữu ích để debug hoặc reset:
| Method | Ý nghĩa |
func.cache_info() |
Trả về NamedTuple gồm hits, misses, maxsize, currsize |
func.cache_clear() |
Xóa toàn bộ dữ liệu trong cache |
# Xem thống kê cache
print(fibonacci_cached.cache_info())
# Output mẫu: CacheInfo(hits=67, misses=36, maxsize=128, currsize=36)
# Xóa cache khi cần thiết (ví dụ: data nguồn thay đổi)
fibonacci_cached.cache_clear()
lru_cacheArguments phải là Hashable:
Tham số truyền vào hàm phải có khả năng hash (int, str, tuple, frozenset).
Truyền list, dict hay set trực tiếp sẽ gây lỗi TypeError: unhashable type. (Mẹo: chuyển list thành tuple nếu cần).
Memory Leak tiềm ẩn:
Nếu dùng maxsize=None, cache sẽ lớn vô hạn theo tập dữ liệu đầu vào. Hãy luôn giới hạn kích thước (vd: maxsize=128, 512, 1024 tùyRAM và miền giá trị).
Side Effects:
Không dùng lru_cache cho các hàm có side-effect (ghi file, gọi API thay đổi trạng thái, query DB không idempotent) vì lần gọi thứ 2 sẽ bị bỏ qua side-effect thực tế.
Nên dùng cho: Hàm thuần túy (pure functions), tính toán nặng (math/recursion), parse cấu hình ít đổi, gọi read-only service nội bộ lặp lại cùng tham số.
Không dùng cho: Hàm phụ thuộc vào biến mutable, state ngầm định, hoặc dữ liệu đầu vào có miền giá trị vô hạn.
Bạn đang gặp bài toán bottleneck hiệu năng nào ở backend Python hay cần tối ưu kiến trúc hệ thống? Hãy chia sẻ với DCSoftTech để cùng thảo luận giải pháp sâu hơn nhé!