C.W.K.
Stream
Lesson 05 of 05 · published

Profiling — cProfile / timeit / 메모리

~15 min · profile, cprofile, timeit, memory

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

측정 없이 최적화 X

최적화 첫 번째 룰 — profile 먼저. 측정 없이 시작도 안 느렸던 코드 빠르게 하느라 시간 보냄. Python 이 stdlib 도구 가짐 — 전체 프로그램에서 시간 어디로 가는지엔 cProfile, 이 snippet 얼마나 빠른지엔 timeit.

cProfile — hot spot 찾기

python -m cProfile -s cumulative script.py 가 스크립트 실행 + cumulative time 정렬 함수 호출 timing 출력. 상단 항목이 최적화 노력 집중할 곳. cProfile 이 오버헤드 있지만 빌트인. py-spy (third-party) 가 sample 기반 + 거의 0 오버헤드.

timeit — micro 벤치마크

timeit.timeit("expression", number=1_000_000) 가 식 반복 시간. timeit 이 GC 와 best-of-N 처리. "이 컴프리헨션이 저 for-loop 보다 빠른가?" 질문에 유용. 주의 — micro 벤치마크가 실세계 성능에 거짓말, 캐시 동작 / 진짜 워크로드 / amortized 비용 반영 X.

메모리 profiling

tracemalloc 가 빌트인 — 할당 추적 시작, 스냅샷, file/line 별 top 할당 표시. memray (Bloomberg) 가 flame graph UI 가진 더 풍부한 외부 도구. 가끔 "왜 이게 8GB 사용?" 엔 tracemalloc 충분, production 메모리 profiling 엔 memray.

원칙: 최적화 전 profile. 상상한 X, 실제 bottleneck 최적화. 그 다음 재 profile 로 확인. 성능 작업의 가장 중요한 단일 습관 — 그리고 가장 자주 skip 되는.

Code

cProfile — 느린 코드 찾기·bash
# cProfile 아래 스크립트 실행, cumulative time 으로 정렬
python -m cProfile -s cumulative my_script.py

# 나중 분석 위해 파일에 저장
python -m cProfile -o profile.stats my_script.py

# 저장된 profile 검사
python -c "import pstats; p = pstats.Stats('profile.stats'); p.sort_stats('cumulative'); p.print_stats(20)"

# 또는 시각적 flame chart 엔 snakeviz:
# pip install snakeviz
# snakeviz profile.stats
코드의 cProfile — 특정 섹션·python
import cProfile
import pstats
import io

def expensive():
    return sum(i * i for i in range(1_000_000))

profiler = cProfile.Profile()
profiler.enable()

expensive()

profiler.disable()

# stats 출력
s = io.StringIO()
ps = pstats.Stats(profiler, stream=s).sort_stats('cumulative')
ps.print_stats(20)
print(s.getvalue())
timeit — micro 벤치마크·python
import timeit

# 두 구현 비교
t1 = timeit.timeit(
    'sum([x*x for x in range(1000)])',
    number=10_000
)
t2 = timeit.timeit(
    'sum(x*x for x in range(1000))',
    number=10_000
)
print(f"list comp: {t1:.3f}s")
print(f"generator: {t2:.3f}s")
# 큰 range 엔 generator 가 약간 빠름 (list materialization X)

# setup 코드와
t3 = timeit.timeit(
    'd["key"]',
    setup='d = {"key": 42}',
    number=10_000_000,
)
print(f"dict 접근: {t3:.3f}s")
tracemalloc — 메모리 profiling·python
import tracemalloc

tracemalloc.start()

# 뭔가 할당
big = [list(range(1000)) for _ in range(1000)]

snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

for stat in top_stats[:5]:
    print(stat)

tracemalloc.stop()

# 메모리 어디로 가는지 pinpoint 에 유용
# 더 깊은 조사엔 memray (Bloomberg 도구)

External links

Exercise

30 번째 피보나치를 재귀적 (캐싱 X) 으로 계산하는 스크립트를 cProfile 로 profile. 가장 많이 호출된 함수 식별. 그 다음 @functools.cache 추가 + 재 profile. 비교. 그 다음 timeit 으로 첫 1000 제곱 합 세 접근 비교 — += 가진 for 루프, sum() 의 list 컴프리헨션, sum() 의 generator expression. 시간 출력.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.