반응형
lru_cache는 Python의 functools 모듈에서 제공하는 데코레이터로, Least Recently Used(LRU) 캐싱 메커니즘을 구현합니다. 함수의 호출 결과를 메모리에 캐싱하여 동일한 입력에 대한 반복 계산을 방지합니다.
기본 사용법
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 실행 예시
print(fibonacci(100)) # 매우 빠르게 계산됨
캐시 크기와 성능 측정
import time
from functools import lru_cache
def measure_time(func, *args):
start = time.time()
result = func(*args)
end = time.time()
return result, end - start
# 캐시 크기 다르게 설정하여 비교
@lru_cache(maxsize=None) # 무제한 캐시
def factorial1(n):
return n * factorial1(n-1) if n else 1
@lru_cache(maxsize=128) # 제한된 캐시
def factorial2(n):
return n * factorial2(n-1) if n else 1
# 성능 비교
for n in [100, 500, 1000]:
result1, time1 = measure_time(factorial1, n)
result2, time2 = measure_time(factorial2, n)
print(f"n={n}:")
print(f"Unlimited cache: {time1:.6f}s")
print(f"Limited cache: {time2:.6f}s")
캐시 정보 확인과 관리
from functools import lru_cache
@lru_cache(maxsize=32)
def expensive_computation(x, y):
# 복잡한 계산 시뮬레이션
return x * y ** 2
# 캐시 통계 확인
def print_cache_info(func):
info = func.cache_info()
print(f"Hits: {info.hits}") # 캐시 히트 횟수
print(f"Misses: {info.misses}") # 캐시 미스 횟수
print(f"Maxsize: {info.maxsize}") # 최대 캐시 크기
print(f"Current size: {info.currsize}") # 현재 캐시 크기
# 캐시 사용 예시
for i in range(5):
expensive_computation(2, 3)
expensive_computation(3, 4)
print_cache_info(expensive_computation)
# 캐시 초기화
expensive_computation.cache_clear()
실제 활용 사례
API 요청 캐싱
import requests
from functools import lru_cache
from datetime import datetime, timedelta
@lru_cache(maxsize=100)
def get_weather_data(city: str, date: str):
"""날씨 API 호출 결과를 캐싱"""
url = f"https://api.weather.com/{city}/{date}"
response = requests.get(url)
return response.json()
# 사용 예시
weather = get_weather_data("seoul", "2024-02-05")
데이터베이스 쿼리 캐싱
from functools import lru_cache
from typing import Optional
import sqlite3
class DatabaseCache:
def __init__(self):
self.conn = sqlite3.connect('database.db')
@lru_cache(maxsize=1000)
def get_user_by_id(self, user_id: int) -> Optional[dict]:
cursor = self.conn.cursor()
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
result = cursor.fetchone()
return dict(zip(['id', 'name', 'email'], result)) if result else None
# 사용 예시
db = DatabaseCache()
user = db.get_user_by_id(123) # 첫 호출: DB 쿼리 실행
user = db.get_user_by_id(123) # 두 번째 호출: 캐시에서 반환
계산 비용이 높은 함수 최적화
import math
from functools import lru_cache
@lru_cache(maxsize=None)
def calculate_complex_formula(x: float, y: float, precision: int) -> float:
"""복잡한 수학적 계산을 캐싱"""
result = 0
for i in range(precision):
result += math.sin(x * i) * math.cos(y * i)
return result
# 성능 측정
def measure_performance():
start = time.time()
for x in range(100):
for y in range(100):
calculate_complex_formula(x/10, y/10, 1000)
end = time.time()
return end - start
주의사항과 최적화 팁
메모리 사용량 고려
# 메모리 사용량 모니터링
import sys
def get_size(obj):
return sys.getsizeof(obj)
@lru_cache(maxsize=100)
def memory_intensive_function(n):
# 큰 리스트 생성
return [i**2 for i in range(n)]
# 메모리 사용량 체크
before = get_size(memory_intensive_function.cache_info())
memory_intensive_function(1000)
after = get_size(memory_intensive_function.cache_info())
print(f"Cache size increased by: {after - before} bytes")
함수 인자 제한
from functools import lru_cache
from typing import Hashable
def make_hashable(obj):
"""객체를 해시 가능한 형태로 변환"""
if isinstance(obj, Hashable):
return obj
elif isinstance(obj, dict):
return tuple((k, make_hashable(v)) for k, v in sorted(obj.items()))
elif isinstance(obj, (list, tuple)):
return tuple(make_hashable(x) for x in obj)
else:
raise TypeError(f"Cannot make {type(obj)} hashable")
@lru_cache(maxsize=128)
def process_data(data):
# 해시 가능한 형태로 변환 후 처리
hashable_data = make_hashable(data)
return str(hashable_data)
lru_cache는 적절히 사용하면 프로그램의 성능을 크게 향상시킬 수 있지만, 메모리 사용량과 캐시 크기의 균형을 잘 고려해야 합니다. 특히 대규모 애플리케이션에서는 캐시 전략을 신중하게 설계해야 합니다.
'파이썬 > Basic' 카테고리의 다른 글
Geopy : 지리 정보 다루기 (2) | 2025.02.10 |
---|---|
함수 하나로 여러 가지 처리하기? Python 오버로딩 (2) | 2024.12.27 |
자료구조 : deque, Queue, heapq (0) | 2024.12.10 |
next()와 제너레이터 표현식 (1) | 2024.12.09 |
순환 참조(Circular Import) 이해하기와 해결 방법 (2) | 2024.12.06 |