cProfile을 사용하여 Python 코드를 프로파일 링하는 방법

파이썬은 가장 빠른 언어는 아니지만 충분히 빠릅니다. 그리고 Python은 프로그래머 시간이 CPU 시간보다 더 중요한 경우에 이상적입니다.

즉, 주어진 Python 앱이 느리면 그냥 빨아 들일 필요가 없습니다. Python 인터프리터의 스톡 설치에 포함 된 도구는 프로그램의 어떤 부분이 느린 지에 대한 자세한 피드백을 제공하고 속도를 높이는 방법에 대한 힌트를 제공 할 수 있습니다.

cProfile 사용 방법

cProfile모듈은 파이썬 프로그램의 실행 시간에 대한 통계를 수집합니다. 전체 앱에서 단일 문 또는 표현식에 이르기까지 모든 것을보고 할 수 있습니다.

다음은 사용 방법의 장난감 예입니다 cProfile.

def add (x, y) : x + = str (y) return x def add_2 (x, y) : if y % 20000 == 0 : z = [] for q in range (0,400000) : z.append ( q) def main () : a = [] for n in range (0,200000) : add (a, n) add_2 (a, n) if __name__ == '__main__': import cProfile cProfile.run ( 'main ( ) ') 

이 예제는 애플리케이션의 main()기능을 실행 main()하고 모든 main()호출 의 성능을 분석 합니다. 프로그램 의 일부만 분석하는 것도 가능  하지만, 가장 일반적으로 사용되는 것은 전체 프로그램을 프로파일 링하는 것입니다.

위의 예를 실행하면 다음과 같은 출력이 표시됩니다.

여기에 표시된 것은 프로그램이 수행 한 모든 함수 호출 목록과 각각에 대한 통계입니다.

  • 맨 위 (파란색 첫 번째 줄)에는 프로파일 링 된 프로그램에서 수행 된 총 호출 수와 총 실행 시간이 표시됩니다. 비재 귀적 호출을 의미하는 "기본 호출"에 대한 그림 이나 호출 스택에서 더 아래로 자신을 호출하지 않는 함수에 대한 직접 호출 도 볼 수 있습니다 .
  • ncalls : 호출 한 수입니다. 두 개의 숫자가 슬래시로 구분 된 경우 두 번째 숫자는 해당 함수에 대한 기본 호출 수입니다.
  • tottime : 다른 함수에 대한 호출을 제외 하고 함수에 소요 된 총 시간 입니다.
  • percall : 대한 호출 당 평균 시간 tottime 고려하여 유도 tottime를 의해 나누어 ncalls .
  • cumtime : 다른 함수에 대한 호출을 포함하여 함수에서 보낸 총 시간입니다.
  • percall (# 2)에 대한 호출 당 평균 시간 cumtime ( cumtime 로 나눈 ncalls ).
  • filename : lineno : 해당 호출의 파일 이름, 줄 번호 및 함수 이름입니다.

cProfile 보고서를 수정하는 방법

기본적 cProfile으로 "표준 이름"으로 출력을 정렬합니다. 즉, 맨 오른쪽 열의 텍스트 (파일 이름, 줄 번호 등)를 기준으로 정렬합니다.

참조를 위해 모든 단일 함수 호출에 대한 일반적인 하향식 보고서를 원하는 경우 기본 형식이 유용합니다. 그러나 병목 현상을 해결하려는 경우 프로그램에서 가장 시간이 많이 걸리는 부분이 먼저 나열되기를 원할 것입니다.

cProfile 약간 다르게 호출하여 이러한 결과를 생성 할 수 있습니다  . 위 프로그램의 하단 부분을 재 작업하여 다른 열 (이 경우 ncalls)로 통계를 정렬하는 방법에 유의하십시오 .

if __name__ == '__main__': import cProfile, pstats profiler = cProfile.Profile () profiler.enable () main () profiler.disable () stats = pstats.Stats (profiler) .sort_stats ( 'ncalls') stats.print_stats () 

결과는 다음과 같습니다.

이 모든 작동 방식은 다음과 같습니다.

  • cProfile.run()별로 유연하지 않은 방법으로 명령을 실행하는 대신 프로파일 링 객체 , profiler.
  • 일부 작업을 프로파일 링하려면 먼저 .enable()프로파일 러 개체 인스턴스를 호출 한 다음 작업을 실행 한 다음을 호출 .disable()합니다. (이것은 프로그램의 일부만 프로파일 링하는 한 가지 방법입니다.)
  • pstats모듈 프로파일 객체에 의해 수집 된 결과를 조정하고 그 결과를 출력하기 위해 사용된다.

프로파일 러 객체를 결합 pstats하여 캡처 된 프로파일 데이터를 조작 할 수 있습니다. 예를 들어 생성 된 통계를 다르게 정렬 할 수 있습니다. 이 예에서 using .sort_stats('ncalls')ncalls열을 기준으로 통계 를 정렬합니다 . 다른 정렬 옵션을 사용할 수 있습니다.

최적화를 위해 cProfile 결과를 사용하는 방법

cProfile 출력에 사용할 수있는 정렬 옵션 을 통해 프로그램에서 잠재적 인 성능 병목 현상을 파악할 수 있습니다.

ncalls

발견 할 수있는 첫 번째이자 가장 중요한 정보 cProfilencalls열 을 통해 가장 자주 호출되는 함수 입니다.

파이썬에서는 단순히 함수를 호출하는 행위만으로도 비교적 많은 오버 헤드가 발생합니다. 일부 함수가 긴 루프에서 반복적으로 호출되면 장기 실행 함수가 아니더라도 성능에 영향을 미칠 수 있습니다.

위의 예에서 함수 add(및 함수 add_2)는 루프에서 반복적으로 호출됩니다. 루프를 add함수 자체 로 이동 하거나 add함수를 완전히 인라인하면 이 문제가 해결됩니다.

tottime

프로그램이 tottime열 을 통해 실행하는 데 대부분의 시간을 소비하는 기능에 대한 또 다른 유용한 통계 세부 정보입니다 .

위의 예에서 add_2함수는 루프를 사용하여 값 비싼 계산을 시뮬레이션하여 tottime점수를 최고로 끌어 올립니다 . tottime점수가 높은 모든 함수는 특히 여러 번 호출되거나 타이트한 루프에있는 경우 자세히 살펴볼 필요가 있습니다.

 함수가 사용되는 컨텍스트 를 항상 고려해야합니다 . 함수가 높지만 tottime한 번만 호출되는 경우 (예 : 프로그램이 시작될 때만) 병목 현상이 발생할 가능성이 적습니다. 그러나 시작 시간을 줄이려는 경우 시작시 호출 된 함수가 다른 모든 것을 대기시키는 지 여부를 알고 싶을 것입니다.

cProfile 데이터를 내보내는 방법

사용하고자하는 경우 cProfile'고급 방식으로 생성 된 통계를이야, 당신은 데이터 파일로 내보낼 수 있습니다 :

stats = pstats.Stats (profiler) stats.dump_stats ( '/ path / to / stats_file.dat') 

이 파일은 pstats모듈 을 사용하여 다시 읽어 들인 다음로 정렬하거나 표시 할 수 pstats있습니다. 데이터는 다른 프로그램에서도 재사용 할 수 있습니다. 두 가지 예 :

  • pyprof2calltree프로필 데이터에서 프로그램의 호출 그래프 및 사용 통계에 대한 자세한 시각화를 렌더링합니다. 이 기사에서는 실제 사용 사례에 대해 자세히 설명합니다.
  • snakeviz또한 cProfile데이터에서 시각화를 생성 하지만 데이터에 대해 다른 표현 (pyprof2calltree의 "불꽃"그래프 대신 "햇살")을 사용합니다.

Python 프로파일 링을위한 cProfile을 넘어서

cProfilePython 애플리케이션을 프로파일 링하는 유일한 방법은 아닙니다. cProfilePython과 함께 번들로 제공된다는 점을 고려할 때 가장 편리한 방법 중 하나입니다. 그러나 다른 사람들은 주목할 가치가 있습니다.

한 프로젝트 py-spy는 호출 활동을 샘플링하여 Python 애플리케이션에 대한 프로필을 빌드합니다. py-spy실행중인 Python 앱을 중지했다가 다시 시작하지 않고 코드베이스를 변경하지 않고도 검사하는 데 사용할 수 있으므로 배포 된 애플리케이션을 프로파일 링하는 데 사용할 수 있습니다. py-spy또한 Python 런타임에서 발생하는 오버 헤드 (예 : 가비지 수집 오버 헤드)에 대한 일부 통계를 생성하지만 cProfile그렇지 않습니다.