벤치마킹 및 프로파일 링

이 장에서는 벤치마킹과 프로파일 링이 성능 문제를 해결하는 데 어떻게 도움이되는지 알아 봅니다.

코드를 작성했고 원하는 결과도 제공한다고 가정 해 보겠습니다.하지만 요구 사항이 변경 되었기 때문에이 코드를 조금 더 빠르게 실행하려면 어떻게해야합니까? 이 경우 코드의 어떤 부분이 전체 프로그램의 속도를 늦추는 지 알아 내야합니다. 이 경우 벤치마킹 및 프로파일 링이 유용 할 수 있습니다.

벤치마킹이란 무엇입니까?

벤치마킹은 표준과 비교하여 무언가를 평가하는 것을 목표로합니다. 그러나 여기서 제기되는 질문은 벤치마킹이 무엇이고 소프트웨어 프로그래밍의 경우 왜 필요한지입니다. 코드 벤치마킹은 코드 실행 속도와 병목 지점의 위치를 ​​의미합니다. 벤치마킹의 주요 이유 중 하나는 코드를 최적화하기 때문입니다.

벤치마킹은 어떻게 작동합니까?

벤치마킹 작업에 대해 이야기한다면 전체 프로그램을 하나의 현재 상태로 벤치마킹하는 것으로 시작해야합니다. 그런 다음 마이크로 벤치 마크를 결합한 다음 프로그램을 더 작은 프로그램으로 분해 할 수 있습니다. 프로그램 내에서 병목 현상을 찾고 최적화하기 위해. 즉, 크고 어려운 문제를 최적화를 위해 일련의 작고 조금 더 쉬운 문제로 나누는 것으로 이해할 수 있습니다.

벤치마킹을위한 Python 모듈

Python에는 기본적으로 벤치마킹을위한 모듈이 있습니다. timeit. 의 도움으로timeit 모듈을 사용하면 메인 프로그램 내에서 작은 Python 코드의 성능을 측정 할 수 있습니다.

다음 Python 스크립트에서 timeit 두 기능을 실행하는 데 걸리는 시간을 추가로 측정하는 모듈 – functionAfunctionB

import timeit
import time
def functionA():
   print("Function A starts the execution:")
   print("Function A completes the execution:")
def functionB():
   print("Function B starts the execution")
   print("Function B completes the execution")
start_time = timeit.default_timer()
functionA()
print(timeit.default_timer() - start_time)
start_time = timeit.default_timer()
functionB()
print(timeit.default_timer() - start_time)

위의 스크립트를 실행하면 아래와 같이 두 함수의 실행 시간을 얻습니다.

산출

Function A starts the execution:
Function A completes the execution:
0.0014599495514175942
Function B starts the execution
Function B completes the execution
0.0017024724827479076

데코레이터 기능을 사용하여 자체 타이머 작성

Python에서는 다음과 같이 작동하는 자체 타이머를 만들 수 있습니다. timeit기준 치수. 의 도움으로 수행 할 수 있습니다.decorator함수. 다음은 사용자 지정 타이머의 예입니다.

import random
import time

def timer_func(func):

   def function_timer(*args, **kwargs):
   start = time.time()
   value = func(*args, **kwargs)
   end = time.time()
   runtime = end - start
   msg = "{func} took {time} seconds to complete its execution."
      print(msg.format(func = func.__name__,time = runtime))
   return value
   return function_timer

@timer_func
def Myfunction():
   for x in range(5):
   sleep_time = random.choice(range(1,3))
   time.sleep(sleep_time)

if __name__ == '__main__':
   Myfunction()

위의 파이썬 스크립트는 임의의 시간 모듈을 가져 오는 데 도움이됩니다. timer_func () 데코레이터 함수를 만들었습니다. 여기에는 function_timer () 함수가 있습니다. 이제 중첩 된 함수는 전달 된 함수를 호출하기 전에 시간을 가져옵니다. 그런 다음 함수가 반환 될 때까지 기다렸다가 종료 시간을 가져옵니다. 이런 식으로 마침내 파이썬 스크립트가 실행 시간을 인쇄하도록 만들 수 있습니다. 스크립트는 아래와 같이 출력을 생성합니다.

산출

Myfunction took 8.000457763671875 seconds to complete its execution.

프로파일 링이란 무엇입니까?

때때로 프로그래머는 메모리 사용, 시간 복잡도 또는 프로그램에 대한 특정 명령 사용과 같은 일부 속성을 측정하여 해당 프로그램의 실제 기능을 측정하려고합니다. 이러한 프로그램에 대한 측정을 프로파일 링이라고합니다. 프로파일 링은 동적 프로그램 분석을 사용하여 이러한 측정을 수행합니다.

이후 섹션에서는 프로파일 링을위한 다양한 Python 모듈에 대해 알아 봅니다.

cProfile – 내장 모듈

cProfile프로파일 링을위한 Python 내장 모듈입니다. 모듈은 장기 실행 프로그램을 프로파일 링하는 데 적합하도록 합리적인 오버 헤드가있는 C 확장입니다. 실행 후 모든 기능과 실행 시간을 기록합니다. 매우 강력하지만 때로는 해석하고 실행하기가 약간 어렵습니다. 다음 예에서는 아래 코드에서 cProfile을 사용하고 있습니다.

def increment_global():

   global x
   x += 1

def taskofThread(lock):

   for _ in range(50000):
   lock.acquire()
   increment_global()
   lock.release()

def main():
   global x
   x = 0

   lock = threading.Lock()

   t1 = threading.Thread(target=taskofThread, args=(lock,))
   t2 = threading.Thread(target= taskofThread, args=(lock,))

   t1.start()
   t2.start()

   t1.join()
   t2.join()

if __name__ == "__main__":
   for i in range(5):
      main()
   print("x = {1} after Iteration {0}".format(i,x))

위의 코드는 thread_increment.py파일. 이제 다음과 같이 명령 줄에서 cProfile로 코드를 실행합니다.

(base) D:\ProgramData>python -m cProfile thread_increment.py
x = 100000 after Iteration 0
x = 100000 after Iteration 1
x = 100000 after Iteration 2
x = 100000 after Iteration 3
x = 100000 after Iteration 4
      3577 function calls (3522 primitive calls) in 1.688 seconds

   Ordered by: standard name

   ncalls tottime percall cumtime percall filename:lineno(function)

   5 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:103(release)
   5 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:143(__init__)
   5 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:147(__enter__)
   … … … …

위의 출력에서 ​​cProfile은 호출 된 모든 3577 함수를 각각에 소요 된 시간과 호출 된 횟수와 함께 인쇄한다는 것이 분명합니다. 다음은 우리가 출력 한 열입니다.

  • ncalls -전화를 건 횟수입니다.

  • tottime − 주어진 함수에 소요 된 총 시간입니다.

  • percall − ncalls로 나눈 tottime의 몫을 나타냅니다.

  • cumtime−이 기능과 모든 하위 기능에 소요 된 누적 시간입니다. 재귀 함수의 경우에도 정확합니다.

  • percall − 원시 호출로 나눈 cumtime의 몫입니다.

  • filename:lineno(function) − 기본적으로 각 기능별 데이터를 제공합니다.