Python으로 코드 속도 10배 빠르게 만드는 `functools.lru_cache` 활용법
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
개발 툴
대상자
- 대상: Python 개발자, 성능 최적화가 필요한 프로젝트 담당자
- 난이도: 중간 (Python 기본 지식과 데코레이터 개념 이해 필요)
핵심 요약
@lru_cache
는 반복 호출 시 계산 결과를 캐시하여 중복 연산 방지 및 속도 향상 가능- 캐시 기능은
maxsize
설정,typed
옵션,cache_info()
/cache_clear()
메서드로 세부 조절 가능 - 적용 사례: 재귀 함수(예: 피보나치), API 호출, DB 쿼리에서 대규모 성능 향상
섹션별 세부 요약
lru_cache
기능 개요
- 인자 기반 키 생성: 위치 인자와 키워드 인자를 해시 가능한 고유 키로 변환
- 캐시 저장 방식: 결과를 딕셔너리에 저장하여 O(1) 조회 가능
- LRU 알고리즘: 사용 빈도 기반으로 오래된 항목 자동 제거
- 통계 및 제어:
.cache_info()
로 캐시 히트/미스 확인,.cache_clear()
로 캐시 초기화
- 기본 사용 예시
- 피보나치 수열
```python
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
```
- 무캐시 시:
fib(35)
실행 시간 ~1.2초 - 캐시 적용 후:
fib(35)
실행 시간 ~20마이크로초
- 실용 사례
- API 호출 최적화
```python
@lru_cache(maxsize=32)
def get_weather(city):
return requests.get(f"https://api.weather.com/{city}").json()
```
- 중복 요청 시: 10번 호출 시 500ms → 0.05ms로 감소
- DB 쿼리 최적화
```python
@lru_cache(maxsize=64)
def fetch_user_profile(user_id):
return User.objects.get(id=user_id)
```
- 100번 요청 시: 10ms → 0.01ms
- 고급 팁 및 주의사항
maxsize
조정:maxsize=None
: 무한 캐시 (메모리 사용 주의)maxsize=128
: 제한된 메모리 사용- 타입 구분:
typed=True
로1
과1.0
을 구분된 키로 처리 - 가변 인자 처리: 리스트/딕셔너리 → 튜플/불변 집합으로 변환
- 캐시 관리:
expensive_operation.cache_clear()
로 수동 초기화
- 성능 비교
| 시나리오 | 무캐시 시간 | lru_cache
시간 | 속도 향상 비율 |
|-----------------------|----------------|------------------|----------------|
| 피보나치(35) 재귀 | ~1.2초 | ~20마이크로초 | 60,000배 |
| API 호출(10번) | ~500ms/호출 | ~0.05ms/호출 | 10,000배 |
| DB 쿼리(100번) | ~10ms/쿼리 | ~0.01ms/쿼리 | 1,000배 |
- 문제 해결 및 팁
- 메모리 사용 과다:
maxsize
값을 합리적으로 설정 - 가변 인자 문제:
tuple()
/frozenset()
으로 전환 - 사이드 이펙트: 순수 함수만 캐시 (I/O/상태 변경 함수는 피함)
- 디스크 기반 캐시:
diskcache
와 결합하여 재시작 시 데이터 보존 - 비동기 함수:
async-lru
라이브러리 사용
결론
- 핵심 팁: timeit
또는 프레임워크 프로파일링 도구로 환경별 실제 성능 측정
- 실무 적용: 핫스팟 함수 식별 후 @lru_cache
적용 및 maxsize
/typed
옵션 조정
- 추천: lru_cache
은 성능 향상, 지연 감소, 확장성 향상의 전략적 도구로 활용해야 함