제퍼넷 로고

Python 코드 성능 최적화: Python 프로파일러 심층 분석

시간

Python 코드 성능 최적화: Python 프로파일러 심층 분석
작성자 별 이미지

Python은 가장 널리 사용되는 프로그래밍 언어 중 하나이지만 대규모 데이터 세트의 경우 실행 시간이 좋지 않은 경우가 많습니다. 프로파일링은 코드 성능을 동적으로 모니터링하고 함정을 식별하는 방법 중 하나입니다. 이러한 함정은 많은 시스템 리소스를 소비하는 버그 또는 잘못 작성된 코드가 있음을 나타낼 수 있습니다. 프로파일러를 사용하면 더 나은 성능을 위해 코드를 최적화하는 데 사용할 수 있는 프로그램의 자세한 통계가 제공됩니다. 예제와 함께 일부 Python 프로파일러를 살펴보겠습니다.

cProfile은 프로그램의 모든 함수 호출을 추적하는 Python의 내장 프로파일러입니다. 함수가 호출된 빈도와 평균 실행 시간에 대한 자세한 정보를 제공합니다. 표준 Python 라이브러리와 함께 제공되므로 명시적으로 설치할 필요가 없습니다. 그러나 모든 단일 함수 호출을 트래핑하고 기본적으로 많은 통계를 생성하므로 라이브 데이터 프로파일링에는 적합하지 않습니다.

import cProfile def sum_(): total_sum = 0 # sum of numbers till 10000 for i in range(0,10001): total_sum += i return total_sum cProfile.run('sum_()')

 

산출
 

4 function calls in 0.002 seconds
Ordered by: standard name
호출 토타임 퍼콜 사정 퍼콜 percall 파일 이름:lineno(함수)
1 0.000 0.000 0.002 0.002 :1( )
1 0.002 0.002 0.002 0.002 cprofile.py:3(합계_)
1 0.000 0.000 0.002 0.002 {내장 메서드 builtins.exec}
1 0.000 0.000 0.000 0.000 {'_lsprof.Profiler' 개체의 '비활성화' 메서드}

출력에서 볼 수 있듯이 cProfile 모듈은 함수의 성능에 대한 많은 정보를 제공합니다. 

  • ncalls = 함수가 호출된 횟수 
  • tottime = 함수에서 보낸 총 시간 
  • percall = 호출당 소요된 총 시간
  • cumtime = 이 기능과 모든 하위 기능에 소요된 누적 시간
  • percall = 호출당 소요된 누적 시간.

Line Profiler는 코드의 라인별 프로파일링을 수행하는 강력한 Python 모듈입니다. 때로는 코드의 핫스팟이 한 줄일 수 있으며 소스 코드에서 직접 찾기가 쉽지 않습니다. Line Profiler는 각 라인이 실행하는 데 걸리는 시간과 최적화를 위해 가장 주의를 기울여야 하는 섹션을 식별하는 데 유용합니다. 그러나 표준 Python 라이브러리와 함께 제공되지 않으며 다음 명령을 사용하여 설치해야 합니다.

pip install line_profiler

from line_profiler import LineProfiler
def sum_arrays(): # creating large arrays arr1 = [3] * (5 ** 10) arr2 = [4] * (3 ** 11) return arr1 + arr2 lp = LineProfiler()
lp.add_function(sum_arrays)
lp.run('sum_arrays()')
lp.print_stats()

산출
 

Timer unit: 1e-07 s
Total time: 0.0562143 s
File: e:KDnuggetsPython_Profilerslineprofiler.py
Function: sum_arrays at line 2
라인 # 조회수 Time 적중당 % 시간 라인 내용
2 데프 sum_arrays():
3 # 큰 배열 생성  
4 1 168563.0  168563.0  30.0 도착1 = [1] * (10 ** 6) 
5 1 3583.0 3583.0 0.6 arr2 = [2] * (2 * 10 ** 7)
6 1 389997.0  389997.0  69.4 반환 arr1 + arr2
  • Line # = 코드 파일의 줄 번호
  • 조회수 = 실행된 횟수
  • 시간 = 라인을 실행하는 데 소요된 총 시간
  • 적중당 = 적중당 소요된 평균 시간
  • % 시간 = 총 기능 시간에 대한 회선에서 소요된 시간의 백분율
  • 줄 내용 = 실제 소스 코드

메모리 프로파일러는 코드의 메모리 할당을 추적하는 Python 프로파일러입니다. 또한 플레임 그래프를 생성하여 메모리 사용량을 분석하고 코드의 메모리 누수를 식별할 수 있습니다. Python 응용 프로그램은 종종 메모리 관리 문제가 발생하기 쉽기 때문에 많은 할당을 유발하는 핫스팟 영역을 식별하는 것도 유용합니다. 메모리 프로파일러는 메모리 소비에 대한 라인별 통계를 프로파일링하며 다음 명령을 사용하여 설치해야 합니다.

pip install memory_profiler

import memory_profiler
import random def avg_marks(): # Genrating Random marks for 50 students for each section sec_a = random.sample(range(0, 100), 50) sec_b = random.sample(range(0, 100), 50) # combined average marks of two sections avg_a = sum(sec_a) / len(sec_a) avg_b = sum(sec_b) / len(sec_b) combined_avg = (avg_a + avg_b)/2 return combined_avg memory_profiler.profile(avg_marks)()

산출
 

Filename: e:KDnuggetsPython_Profilersmemoryprofiler.py
라인 # 메모리 사용량 증가 발생 라인 내용
4 21.7 MiB  21.7 MiB  1 def avg_marks():
5 # 각 섹션에 대해 50명의 학생에 대한 임의 점수 생성
6 21.8 MiB 0.0 MiB  1 sec_a = random.sample(범위(0, 100), 50)
7 21.8 MiB 0.0 MiB  1 sec_b = random.sample(범위(0, 100), 50)
8
9 # 두 섹션의 합산 평균 점수
10 21.8 MiB 0.0 MiB  1 avg_a = 합(sec_a) / 길이(sec_a)
11 21.8 MiB 0.0 MiB  1 avg_b = 합(sec_b) / 길이(sec_b)
12 21.8 MiB 0.0 MiB  1 결합된_avg = (avg_a + avg_b)/2
13 21.8 MiB 0.0 MiB  1 Combine_avg 반환
  • Line # = 코드 파일의 줄 번호
  • Mem 사용량 = Python Interpreter의 메모리 사용량
  • 증분 = 이전 라인과 현재 라인에서 소비된 메모리의 차이
  • Occurences = 코드 라인이 실행된 횟수
  • 줄 내용 = 실제 소스 코드

Timeit은 작은 코드 스니펫의 성능을 평가하기 위해 특별히 설계된 내장 Python 라이브러리입니다. 코드의 성능 병목 현상을 식별하고 최적화하여 더 빠르고 효율적인 코드를 작성할 수 있도록 도와주는 강력한 도구입니다. 알고리즘의 다른 구현은 timeit 모듈을 사용하여 비교할 수도 있지만 단점은 이를 사용하여 코드 블록의 개별 라인만 분석할 수 있다는 것입니다.

import timeit
code_to_test = """
# creating large arrays
arr1 = [3] * (5 ** 10)
arr2 = [4] * (3 ** 11)
arr1 + arr2 """
elapsed_time = timeit.timeit(code_to_test, number=10)
print(f'Elapsed time: {elapsed_time}')

산출
 

Elapsed time: 1.3809973997995257

그 사용은 더 작은 코드 스니펫을 평가하는 것으로만 제한됩니다. 주목해야 할 한 가지 중요한 점은 코드 스니펫이 실행될 때마다 다른 시간에 표시된다는 것입니다. 컴퓨터에서 실행 중인 다른 프로세스가 있을 수 있고 리소스 할당이 실행마다 다를 수 있으므로 모든 변수를 제어하고 각 실행에 대해 동일한 처리 시간을 달성하기가 어렵기 때문입니다.

Yappi는 성능 병목 현상을 쉽게 식별할 수 있는 Python 프로파일러입니다. C로 작성되어 가장 효율적인 프로파일러 중 하나입니다. 여기에는 집중해야 하는 코드의 특정 부분만 프로파일링할 수 있는 사용자 정의 가능한 API가 있어 프로파일링 프로세스를 더 잘 제어할 수 있습니다. 동시 코루틴을 프로파일링하는 기능은 코드가 작동하는 방식에 대한 심층적인 이해를 제공합니다.  

import yappi
def sum_arrays(): # creating large arrays arr1 = [3] * (5 ** 10) arr2 = [4] * (3 ** 11) return arr1 + arr2 with yappi.run(builtins=True): final_arr = sum_arrays() print("n--------- Function Stats -----------")
yappi.get_func_stats().print_all() print("n--------- Thread Stats -----------")
yappi.get_thread_stats().print_all() print("nYappi Backend Types: ",yappi.BACKEND_TYPES)
print("Yappi Clock Types: ", yappi.CLOCK_TYPES)

참고 : 다음 명령을 사용하여 yappi를 설치합니다. pip install yappi

 
산출
 

--------- Function Stats ----------- Clock type: CPU
Ordered by: totaltime, desc
name 전화 태브그
..lersyappiProfiler.py:4 sum_arrays 1 0.109375 0.109375 0.109375
내장. 다음 1 0.000000 0.000000 0.000000
.. _GeneratorContextManager.__exit__ 1 0.000000 0.000000 0.000000

——— 스레드 통계 ———–

 

name id TID scnt
_메인스레드 0 15148 0.187500  1
Yappi Backend Types: {'NATIVE_THREAD': 0, 'GREENLET': 1}
Yappi Clock Types: {'WALL': 0, 'CPU': 1}

내장 모듈에 대해 모듈 이름을 다르게 지정해야 합니다. 그렇지 않으면 가져오기에서 실제 내장 모듈 대신 모듈(예: Python 파일)을 가져옵니다.

개발자는 이러한 프로파일러를 사용하여 코드의 병목 현상을 식별하고 어떤 구현이 가장 적합한지 결정할 수 있습니다. 올바른 도구와 약간의 노하우만 있으면 누구나 Python 코드를 다음 수준의 성능으로 끌어올릴 수 있습니다. 따라서 Python 성능 최적화를 최적화하고 새로운 차원으로 도약하는 것을 지켜보십시오!

이 글을 읽으셨다니 기쁘고 소중한 경험이 되셨기를 바랍니다.
 
 
칸월 메린 데이터 과학 및 의료 분야의 AI 응용에 큰 관심을 가진 소프트웨어 개발자 지망생입니다. Kanwal은 APAC 지역의 Google Generation Scholar 2022로 선정되었습니다. Kanwal은 유행하는 주제에 대한 기사를 작성하여 기술 지식을 공유하는 것을 좋아하며 기술 산업에서 여성의 대표성을 개선하는 데 열정적입니다.
 

spot_img

최신 인텔리전스

spot_img