본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] 성능 최적화의 열쇠, cProfile 결과를 분석하여 3가지 병목 지점을 찾는 방법과 해결책

by Papa Martino V 2026. 3. 14.
728x90

cProfile 분석
cProfile 분석

 

파이썬은 개발 속도가 빠르지만, 대규모 데이터를 처리하거나 복잡한 알고리즘을 수행할 때 성능 한계에 부딪히기 쉽습니다. 단순히 "코드가 느리다"는 직감만으로는 복잡한 시스템의 성능을 개선할 수 없습니다. 이때 필요한 것이 바로 결정론적 프로파일링(Deterministic Profiling) 도구인 cProfile입니다. 본 가이드에서는 파이썬 표준 라이브러리인 cProfile을 활용해 실행 시간을 데이터로 확인하고, 실제 서비스에서 발생할 수 있는 3가지 주요 병목 지점을 찾아내는 전문적인 분석 방법을 제시합니다.


1. cProfile 분석 데이터의 핵심 지표 이해 (표 분석)

cProfile을 실행하면 수많은 열(column) 데이터가 출력됩니다. 각 지표가 무엇을 의미하는지 정확히 아는 것이 분석의 시작입니다.

지표 (Column) 의미 분석 가치 및 차이점
ncalls 함수 호출 횟수 재귀 호출이나 루프 내 과다 호출 확인
tottime 해당 함수에서 소비된 총 시간 하위 함수 호출 시간을 제외한 순수 로직 시간
percall (1) tottime / ncalls 1회 호출당 소요되는 평균 순수 시간
cumtime 누적 시간 하위 함수 호출을 포함하여 소비된 총 시간
percall (2) cumtime / ncalls 하위 함수 포함, 1회 호출당 평균 누적 시간
filename:lineno 위치 정보 병목이 발생하는 소스 코드의 정확한 위치

2. cProfile을 활용한 3가지 병목 지점 해결 방법

방법 1: 과도한 루프와 알고리즘 복잡도 해결

tottime이 비정상적으로 높은 경우, 해당 함수 내부의 연산 로직(예: 중첩 for문)이 무겁다는 신호입니다. 이때는 알고리즘의 시간 복잡도($O(n)$ 등)를 검토해야 합니다.

방법 2: 외부 I/O 및 API 호출 지연 해결

함수 자체의 tottime은 낮지만 cumtime이 매우 높다면, 내부에서 호출하는 하위 함수(네트워크 요청, DB 쿼리)가 병목일 가능성이 큽니다. 캐싱이나 비동기 처리가 필요합니다.

방법 3: 빈번한 함수 호출(Function Call Overhead) 해결

ncalls 수치가 수백만 번에 달한다면, 파이썬의 함수 호출 오버헤드가 누적되어 성능을 저하시키는 것입니다. 내장 함수를 사용하거나 로직을 인라인화하여 해결합니다.


3. Sample Example: 병목 코드 분석 및 최적화 실습

다음은 의도적으로 병목을 만든 코드와 cProfile 분석 적용 예시입니다.


import cProfile
import pstats
import time

# [병목 발생 예제]
def heavy_computation():
    # 방법 1: 불필요한 연산 반복
    result = 0
    for i in range(1000000):
        result += i
    return result

def slow_external_call():
    # 방법 2: 대기 시간이 발생하는 작업
    time.sleep(0.5)

def main():
    for _ in range(5):
        heavy_computation()
        slow_external_call()

# 프로파일링 실행 및 분석
if __name__ == "__main__":
    profiler = cProfile.Profile()
    profiler.enable()
    main()
    profiler.disable()
    
    # 결과를 cumtime 기준으로 정렬하여 상위 10개 출력
    stats = pstats.Stats(profiler).sort_stats('cumulative')
    stats.print_stats(10)

위 예제를 실행하면 slow_external_callcumtime이 가장 높게 나타나며, 실제 로직 수행보다 '대기'에 많은 시간이 소요됨을 수치로 증명할 수 있습니다.


4. 전문적인 성능 분석을 위한 팁

  • pstats 모듈 활용: 단순 텍스트 출력보다 pstats를 사용하여 바이너리 로그를 저장하고, 나중에 다양한 기준(calls, time 등)으로 정렬하여 분석하세요.
  • 시각화 도구 병행: snakeviz와 같은 도구를 사용하면 cProfile 결과(prof 파일)를 브라우저에서 인터랙티브한 그래프로 확인할 수 있어 직관적입니다.
  • 운영 환경 주의: 프로파일링 자체도 오버헤드가 있으므로, 운영 환경보다는 스테이징 환경에서 테스트하는 것이 원칙입니다.

내용의 출처

  • Python Software Foundation. "The Python Profilers: cProfile and profile." Official Documentation.
  • High Performance Python: Practical Performant Programming for Humans by Micha Gorelick and Ian Ozsvald.
  • Brett Slatkin. "Effective Python: 90 Specific Ways to Write Better Python."
728x90