본문 바로가기
C.W.K.
Stream
Lesson 05 of 05 · published

성능 분석 — 추측 대신 병목을 재기

~15 min · profile, cprofile, timeit, memory

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

최적화는 측정부터야. python -m cProfile -s cumulative script.py는 함수별 누적 시간을 보여줘 실제 병목 지점을 찾게 하고, 표본 기반 py-spy는 실행 부담이 거의 없어. 바꾼 뒤에는 같은 프로파일을 다시 떠 병목이 정말 줄거나 이동했는지 확인해.

timeit은 작은 식을 여러 번 실행해 미세 성능 측정을 돕고 쓰레기 수집과 반복 측정을 다뤄. 하지만 캐시·입출력·메모리 할당·실제 입력 분포를 빠뜨린 짧은 반복문이 운영 환경 성능을 대신하진 않아. 환경과 작업량을 숫자 옆에 기록해.

메모리는 내장 tracemalloc로 할당 기록을 파일·줄별로 비교하고, 더 깊은 운영 환경 분석에는 memray 같은 도구를 써. 측정하지 않은 곳을 빠르게 만드는 건 최적화가 아니라 추측이야.

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
코드의 일부만 프로파일하기·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으로 작은 선택 비교하기·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 없음)

# setup 코드와
t3 = timeit.timeit(
    'd["key"]',
    setup='d = {"key": 42}',
    number=10_000_000,
)
print(f"dict 접근: {t3:.3f}s")
tracemalloc로 메모리 할당 찾기·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

캐시 없는 재귀 fib(30)을 cProfile로 재 가장 많이 호출된 함수를 찾고 functools.cache를 붙여 다시 비교해. 이어 첫 1000개 정수의 제곱 합을 for 반복문, 리스트 컴프리헨션을 넣은 sum, 제너레이터를 넣은 sum으로 각각 timeit해.

Progress

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

댓글 0

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

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