[python] Python 스크립트를 벤치마킹하는 간단한 방법이 있습니까?

일반적으로 쉘 명령을 사용 time합니다. 내 목적은 데이터가 작은, 중간, 큰 또는 매우 큰 집합인지, 얼마나 많은 시간과 메모리 사용량이 될지 테스트하는 것입니다.

이 작업을 수행하는 Linux 용 도구 또는 Python 용 도구가 있습니까?



답변

한 번 봐 가지고 timeit , 파이썬 프로파일pycallgraph을 . 또한 ” SnakeViznikicc 언급 하여 아래 주석 을 확인하십시오 . 유용한 프로파일 링 데이터의 또 다른 시각화를 제공합니다.

timeit

def test():
    """Stupid test function"""
    lst = []
    for i in range(100):
        lst.append(i)

if __name__ == '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test"))

    # For Python>=3.5 one can also write:
    print(timeit.timeit("test()", globals=locals()))

기본적으로 Python 코드를 문자열 매개 변수로 전달할 수 있으며 지정된 시간에 실행되고 실행 시간을 인쇄합니다. 문서 의 중요한 부분 :

timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)Timer주어진 문, 설정
코드 및 타이머 함수
로 인스턴스를 만들고 숫자 실행 으로 timeit메서드를
실행합니다. 선택적 globals 인수는 코드를 실행할 네임 스페이스를 지정합니다.

… 그리고 :

Timer.timeit(number=1000000)
시간 주 문 실행. 이것은 setup 문을 한 번 실행 한 다음 기본 문을 여러 번 실행하는 데 걸리는 시간 (초 단위로 측정)을 float로 반환합니다. 인수는 루프를 통과하는 횟수이며 기본값은 백만입니다. 기본 문, 설정 문 및 사용할 타이머 함수가 생성자에 전달됩니다.

참고 :
기본적 timeit으로 garbage collection타이밍 동안 일시적으로 꺼집니다 . 이 접근 방식의 장점은 독립적 인 타이밍을 더 비슷하게 만든다는 것입니다. 이 단점은 GC가 측정되는 기능의 성능에 중요한 구성 요소가 될 수 있다는 것입니다. 그렇다면 GC를 설정 문자열 의 첫 번째 문으로 다시 활성화 할 수 있습니다 . 예를 들면 :

timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()

프로파일 링

프로파일 링은 무슨 일이 일어나고 있는지에 대한 훨씬 더 자세한 아이디어 를 제공합니다 . 다음 은 공식 문서 의 “인스턴트 예제”입니다 .

import cProfile
import re
cProfile.run('re.compile("foo|bar")')

당신에게 줄 것 :

      197 function calls (192 primitive calls) in 0.002 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 re.py:212(compile)
     1    0.000    0.000    0.001    0.001 re.py:268(_compile)
     1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
     1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
     4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
   3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)

이 두 모듈 모두 병목 지점을 찾을 수있는 위치에 대한 아이디어를 제공해야합니다.

또한의 출력을 이해하려면 이 게시물을profile 살펴보십시오.

pycallgraph

NOTE pycallgraph는 2018 년 2 월부터 공식적으로 폐기되었습니다 . 2020 년 12 월 현재 Python 3.6에서는 여전히 작업 중이었습니다. 파이썬이 프로파일 링 API를 노출하는 방법에 핵심적인 변경 사항이없는 한 유용한 도구로 남아 있어야합니다.

이 모듈 은 graphviz를 사용하여 다음과 같은 콜 그래프를 만듭니다.

callgraph 예

색상별로 가장 많이 사용한 경로를 쉽게 확인할 수 있습니다. pycallgraph API를 사용하거나 패키지화 된 스크립트를 사용하여 만들 수 있습니다.

pycallgraph graphviz -- ./mypythonscript.py

그러나 오버 헤드는 상당히 상당합니다. 따라서 이미 오래 실행되는 프로세스의 경우 그래프를 만드는 데 시간이 걸릴 수 있습니다.


답변

나는 간단한 데코레이터를 사용하여

def st_time(func):
    """
        st decorator to calculate the total time of a func
    """

    def st_func(*args, **keyArgs):
        t1 = time.time()
        r = func(*args, **keyArgs)
        t2 = time.time()
        print "Function=%s, Time=%s" % (func.__name__, t2 - t1)
        return r

    return st_func


답변

timeit내가 쓴 있도록 모듈은 느리고 이상한 :

def timereps(reps, func):
    from time import time
    start = time()
    for i in range(0, reps):
        func()
    end = time()
    return (end - start) / reps

예:

import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)

나를 위해 그것은 말한다 :

python can do 40925 os.listdir('/') per second

이것은 원시적 인 종류의 벤치마킹이지만 충분합니다.


답변

나는 보통 time ./script.py얼마나 걸리는지 빨리 확인합니다. 그래도 메모리는 표시되지 않지만 적어도 기본값은 아닙니다. /usr/bin/time -v ./script.py메모리 사용량을 포함하여 많은 정보를 얻는 데 사용할 수 있습니다 .


답변

모든 메모리 요구 사항을위한 메모리 프로파일 러.

https://pypi.python.org/pypi/memory_profiler

pip 설치를 실행합니다.

pip install memory_profiler

라이브러리 가져 오기 :

import memory_profiler

프로파일 링하려는 항목에 데코레이터를 추가합니다.

@profile
def my_func():
    a = [1] * (10 ** 6)
    b = [2] * (2 * 10 ** 7)
    del b
    return a

if __name__ == '__main__':
    my_func()

코드를 실행하십시오.

python -m memory_profiler example.py

출력 받기 :

 Line #    Mem usage  Increment   Line Contents
 ==============================================
 3                           @profile
 4      5.97 MB    0.00 MB   def my_func():
 5     13.61 MB    7.64 MB       a = [1] * (10 ** 6)
 6    166.20 MB  152.59 MB       b = [2] * (2 * 10 ** 7)
 7     13.61 MB -152.59 MB       del b
 8     13.61 MB    0.00 MB       return a

예제는 위에 링크 된 문서의 것입니다.


답변

nose 와 플러그인 중 하나 , 특히이 플러그인을 살펴보십시오 .

일단 설치되면 nose는 경로에있는 스크립트이며 일부 Python 스크립트가 포함 된 디렉토리에서 호출 할 수 있습니다.

$: nosetests

이것은 현재 디렉토리의 모든 파이썬 파일을 살펴보고 테스트로 인식하는 모든 함수를 실행합니다. 예를 들어 이름에 test_라는 단어가있는 모든 함수를 테스트로 인식합니다.

따라서 test_yourfunction.py라는 파이썬 스크립트를 생성하고 다음과 같이 작성할 수 있습니다.

$: cat > test_yourfunction.py

def test_smallinput():
    yourfunction(smallinput)

def test_mediuminput():
    yourfunction(mediuminput)

def test_largeinput():
    yourfunction(largeinput)

그런 다음 실행해야

$: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py

프로필 파일을 읽으려면 다음 파이썬 줄을 사용하십시오.

python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)"


답변

timeit매우 느리다는 점에 주의하세요. 중간 프로세서에서 초기화 (또는 함수 실행)하는 데 12 초가 걸립니다. 이 대답을 테스트 할 수 있습니다.

def test():
    lst = []
    for i in range(100):
        lst.append(i)

if __name__ == '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second

time대신 사용하겠습니다 . 내 PC에서 결과를 반환합니다.0.0

import time

def test():
    lst = []
    for i in range(100):
        lst.append(i)

t1 = time.time()

test()

result = time.time() - t1
print(result) # 0.000000xxxx