timeit 모듈 사용법


351

나는 무엇의 개념을 이해 timeit하지만 내 코드에서 구현하는 방법을 모르겠습니다.

어떻게 두 가지 기능 말을 비교할 수 insertion_sorttim_sort함께 timeit?

답변:


266

timeit이 작동 하는 방법 은 설정 코드를 한 번 실행 한 다음 일련의 명령문을 반복해서 호출하는 것입니다. 따라서 정렬을 테스트하려는 경우 전체 정렬에서 한 번의 패스가 이미 정렬 된 데이터가있는 다음 패스에 영향을 미치지 않도록주의해야합니다 (물론 Timsort가 최상의 성능을 발휘하기 때문에 실제로 빛나게합니다) 데이터가 이미 부분적으로 주문 된 경우).

정렬 테스트를 설정하는 방법의 예는 다음과 같습니다.

>>> import timeit

>>> setup = '''
import random

random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''

>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145

일련의 명령문은 모든 패스에서 정렬되지 않은 데이터의 새로운 사본을 만듭니다.

또한 측정 제품군을 7 회 실행하고 최상의 시간 만 유지하는 타이밍 기술에 유의하십시오. 이는 시스템에서 실행중인 다른 프로세스로 인한 측정 왜곡을 줄이는 데 실제로 도움이됩니다.

이것들은 timeit을 올바르게 사용하는 팁입니다. 도움이 되었기를 바랍니다 :-)


8
예, 목록 사본이 포함되어 있습니다 (정렬 자체에 비해 매우 빠름). 그래도 복사하지 않으면 첫 번째 패스가 목록을 정렬하고 나머지 패스는 작업을 수행 할 필요가 없습니다. 정렬 시간 만 알고 싶다면 위와 달리없이 위의 내용을 실행 timsort(a)하고 차이를보십시오 :-)
Raymond Hettinger

각 설정마다 7 번 반복 한 다음 평균을 설정하는 것이 좋습니다. 다른 방향으로 돌아 가기보다는 이렇게하면 다른 프로세스로 인한 각 급상승이 평균보다 전체적으로 무시 될 가능성이 높습니다.
최대

75
@max 타이밍 평균 대신 min ()을 사용하십시오. 그것은 저, Tim Peters, Guido van Rossum의 추천입니다. 가장 빠른 시간은 캐시가로드되고 시스템이 다른 작업으로 바쁠 때 알고리즘이 수행 할 수있는 최상의 시간을 나타냅니다. 모든 타이밍이 시끄 럽습니다. 가장 빠른 시간이 가장 시끄 럽습니다. 가장 빠른 타이밍이 가장 재현성이 높고 따라서 두 가지 다른 구현을 타이밍 할 때 가장 유용하다는 것을 쉽게 알 수 있습니다.
Raymond Hettinger

4
1000 개의 입력에 대한 평균 (웰, 합계, 동등)을 계산합니다 . 그런 다음 7 번 반복하고 최소값을 취하십시오 . 평균 (최상의 경우는 아님) 알고리즘 복잡성을 원하기 때문에 평균 1000 개 이상의 입력이 필요합니다. 당신이 준 이유에 대한 최소값이 필요합니다. 나는 하나의 입력을 선택하고 알고리즘을 7 번 실행하고 최소값을 취함으로써 접근 방식을 향상시킬 수 있다고 생각했습니다. 그런 다음 1000 개의 다른 입력에 대해 반복하고 평균을 취합니다. 내가 알지 못하는 것은 당신이 .repeat(7,1000)이미 같은 씨앗을 사용하여 이것을 한다는 것입니다 ! 따라서 귀하의 솔루션은 완벽한 IMO입니다.
최대

5
난 단지 당신이 7000 개 실행의 예산을 할당하는 방법 (예를 들어, 것을 추가 할 수 있습니다 .repeat(7, 1000).repeat(2, 3500)대가 .repeat(35, 200) 때문에 시스템 부하에 대한 오류로 인해 입력 변동에 오류 비교하는 방법에 의존한다. 극단적 인 경우 시스템에 항상 부하가 큰 상태에서 실행 시간 분포 왼쪽에 길고 얇은 꼬리가 나타나는 경우 (드문 유휴 상태에서 시스템을 잡을 때) .repeat(7000,1)더 유용한 경우 .repeat(7,1000)가 있습니다. 7,000 회 이상의 예산을 책정 할 수 없습니다.
최대

277

timeit대화식 Python 세션에서 사용하려는 경우 두 가지 편리한 옵션이 있습니다.

  1. IPython 쉘을 사용하십시오 . 편리한 %timeit특수 기능이 있습니다.

    In [1]: def f(x):
       ...:     return x*x
       ...: 
    
    In [2]: %timeit for x in range(100): f(x)
    100000 loops, best of 3: 20.3 us per loop
  2. 표준 Python 인터프리터에서는 대화식 세션 중에 이전에 정의한 함수 및 기타 이름을 __main__setup 문에서 가져 와서 액세스 할 수 있습니다 .

    >>> def f(x):
    ...     return x * x 
    ... 
    >>> import timeit
    >>> timeit.repeat("for x in range(100): f(x)", "from __main__ import f",
                      number=100000)
    [2.0640320777893066, 2.0876040458679199, 2.0520210266113281]

97
from __main__ import f기술 을 보여주기 위해 +1 . 나는 이것이 널리 알려져 있다고 생각하지 않습니다. 함수 또는 메소드 호출 시간이 초과되는 경우에 유용합니다. 다른 경우 (일련의 단계 타이밍)에는 함수 호출 오버 헤드가 발생하므로 도움이되지 않습니다.
레이몬드 Hettinger

15
당신은 할 수 있습니다%timeit f(x)
qed

참고 : "import f"설정은 일반적인 로컬 코드에서 글로벌 함수 호출 (짧은 빠른 함수)을 정확하게 반영하지 않는 빠른 로컬 읽기 액세스에 액세스합니다. Py3.5 +에서 실제 전역을 제공 할 수 있습니다 : "버전 3.5에서 변경 : 전역 매개 변수 옵션이 추가되었습니다."; 불가피한 timeit 모듈의 전역 전에 (이는 말이되지 않습니다). 아마도 호출 코드의 전역 ( sys._getframe(N).f_globals)이 처음부터 기본값이었을 것입니다.
kxr

140

비밀로 알려 드리겠습니다. 사용하는 가장 좋은 방법 timeit은 명령 줄에 있습니다.

명령 행에서 timeit적절한 통계 분석을 수행합니다. 가장 짧은 실행 시간을 알려줍니다. 이것은 모두 좋기 때문에 좋습니다타이밍의 오류가 양수 . 따라서 가장 짧은 시간은 오류가 가장 적습니다. 컴퓨터가 계산할 수있는 것보다 빠르게 계산할 수 없기 때문에 부정적인 오류를 얻을 수있는 방법이 없습니다!

따라서 명령 행 인터페이스는 다음과 같습니다.

%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop

아주 간단합니다.

당신은 물건을 설정할 수 있습니다 :

%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop

유용합니다!

여러 줄을 원한다면 쉘의 자동 연속을 사용하거나 별도의 인수를 사용할 수 있습니다.

%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop

그것은 설정을 제공합니다

x = range(1000)
y = range(100)

그리고 시간

sum(x)
min(y)

더 긴 스크립트를 원한다면 timeitPython 스크립트 내부 로 이동하고 싶을 수도 있습니다 . 명령 줄에서 분석과 타이밍이 더 좋기 때문에 피하는 것이 좋습니다. 대신 쉘 스크립트를 만드는 경향이 있습니다.

 SETUP="

 ... # lots of stuff

 "

 echo Minmod arr1
 python -m timeit -s "$SETUP" "Minmod(arr1)"

 echo pure_minmod arr1
 python -m timeit -s "$SETUP" "pure_minmod(arr1)"

 echo better_minmod arr1
 python -m timeit -s "$SETUP" "better_minmod(arr1)"

 ... etc

여러 초기화로 인해 시간이 조금 더 걸릴 수 있지만 일반적으로 큰 문제는 아닙니다.


하지만 사용 하고 싶다면timeit 모듈 내부에?

간단한 방법은 다음과 같습니다.

def function(...):
    ...

timeit.Timer(function).timeit(number=NUMBER)

그 누적 당신 (제공 하지 그 횟수만큼 실행하는 최소한이 !) 시간을줍니다.

좋은 분석을 얻으려면 .repeat최소 사용 하고 사용하십시오.

min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))

일반적으로 오버 헤드를 낮추는 functools.partial대신 이것을 결합해야합니다 lambda: .... 따라서 다음과 같은 것을 가질 수 있습니다.

from functools import partial

def to_time(items):
    ...

test_items = [1, 2, 3] * 100
times = timeit.Timer(partial(to_time, test_items)).repeat(3, 1000)

# Divide by the number of repeats
time_taken = min(times) / 1000

당신은 또한 할 수 있습니다 :

timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)

명령 줄에서 인터페이스에 더 가까운 것을 제공 하지만 훨씬 덜 멋진 방식으로 제공합니다. 은 "from __main__ import ..."당신이 만든 인공 환경 내부에 메인 모듈의 코드를 사용할 수 있습니다 timeit.

이것은 편리한 래퍼 Timer(...).timeit(...)이므로 타이밍에 특히 좋지 않습니다. 나는 Timer(...).repeat(...)위에서 보여준 것처럼 개인적으로 사용하는 것을 훨씬 선호합니다 .


경고

timeit사방에 몇 가지 경고가 있습니다.

  • 오버 헤드는 계산되지 않습니다. x += 1추가 시간이 얼마나 걸리는지 알아 보려면 시간을 정하고 싶다고 가정 해보십시오 .

    >>> python -m timeit -s "x = 0" "x += 1"
    10000000 loops, best of 3: 0.0476 usec per loop

    글쎄, 그것은 0.0476 µs 가 아닙니다 . 당신은 그것 보다 적은 것을 알고 있습니다. 모든 오류는 양수입니다.

    따라서 순수한 오버 헤드를 시도하고 찾으십시오 .

    >>> python -m timeit -s "x = 0" ""      
    100000000 loops, best of 3: 0.014 usec per loop

    타이밍만으로도 30 % 의 우수한 오버 헤드입니다! 이로 인해 상대 타이밍이 크게 왜곡 될 수 있습니다. 그러나 당신은 정말로 타이밍을 추가하는 것에 관심을 가졌습니다. 조회 시간 x도 오버 헤드에 포함되어야합니다.

    >>> python -m timeit -s "x = 0" "x"
    100000000 loops, best of 3: 0.0166 usec per loop

    그 차이는 그다지 크지 않지만 거기에 있습니다.

  • 돌연변이 방법은 위험합니다.

    >>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
    10000000 loops, best of 3: 0.0436 usec per loop

    그러나 그것은 완전히 잘못입니다! x첫 번째 반복 후 빈 목록입니다. 다시 초기화해야합니다.

    >>> python -m timeit "x = [0]*100000" "while x: x.pop()"
    100 loops, best of 3: 9.79 msec per loop

    그러나 오버 헤드가 많이 있습니다. 별도로 설명하십시오.

    >>> python -m timeit "x = [0]*100000"                   
    1000 loops, best of 3: 261 usec per loop

    여기서 오버 헤드를 빼는 것은 오버 헤드가 시간의 작은 부분 이기 때문에 합리적 입니다.

    예를 들어 삽입 정렬과 팀 정렬 모두 이미 정렬 된 목록에 대해 완전히 특이한 타이밍 동작을 가지고 있음을 주목할 가치가 있습니다. 즉 random.shuffle, 타이밍을 방해하지 않으려면 여러 종류 가 필요합니다 .


1
usec 무엇을 의미합니까? 마이크로 초입니까?
Hasan Iqbal 2016

2
@HasanIqbalAnik 예.
Veedrac

@StefanPochmann 여러 번 샘플링하지 않기 때문입니다.
Veedrac


@Veedrac 순수한 타이밍 오버 헤드를 빼는 것에 대한 진술을 고려할 때 인수가 주어지지 않을 때 진술을 timeit실행합니다 pass. 물론 시간이 걸립니다. 인수가 주어지면, pass없는 일부 뺀 때문에, 실행 얻을 0.014모든 타이밍에서 usecs하는 것은 잘못된 것입니다.
Arne

99

두 블록의 코드 / 함수를 빠르게 비교하려면 다음을 수행하십시오.

import timeit

start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)

43

timeit을 사용하는 가장 쉬운 방법은 명령 줄에서 찾는 것입니다.

주어진 test.py :

def InsertionSort(): ...
def TimSort(): ...

다음과 같이 timeit을 실행하십시오.

% python -mtimeit -s'import test' 'test.InsertionSort()'
% python -mtimeit -s'import test' 'test.TimSort()'

18

나를 위해, 이것은 가장 빠른 방법입니다.

import timeit
def foo():
    print("here is my code to time...")


timeit.timeit(stmt=foo, number=1234567)

12
# Генерация целых чисел

def gen_prime(x):
    multiples = []
    results = []
    for i in range(2, x+1):
        if i not in multiples:
            results.append(i)
            for j in range(i*i, x+1, i):
                multiples.append(j)

    return results


import timeit

# Засекаем время

start_time = timeit.default_timer()
gen_prime(3000)
print(timeit.default_timer() - start_time)

# start_time = timeit.default_timer()
# gen_prime(1001)
# print(timeit.default_timer() - start_time)

7

이것은 잘 작동합니다 :

  python -m timeit -c "$(cat file_name.py)"

Windows에 해당하는 것은 무엇입니까?
Shailen

2
스크립트에 필요한 경우 매개 변수를 어떻게 전달합니까?
Juuso Ohtonen

3

다음 각각에 동일한 사전을 설정하고 실행 시간을 테스트하십시오.

설정 인수는 기본적으로 사전을 설정합니다.

숫자는 코드를 1000000 번 실행하는 것입니다. 설정이 아니라 표준

이것을 실행하면 색인이 얻는 것보다 훨씬 빠르다는 것을 알 수 있습니다. 여러 번 실행하여 볼 수 있습니다.

코드는 기본적으로 사전에서 c 값을 가져 오려고 시도합니다.

import timeit

print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))

내 결과는 다음과 같습니다.

색인으로 : 0.20900007452246427

으로 : 0.54841166886888


어떤 버전의 파이썬을 사용하고 있습니까?
에두아르도

3

단순히 전체 코드를 timeit의 인수로 전달하십시오.

import timeit

print(timeit.timeit(

"""   
limit = 10000
prime_list = [i for i in range(2, limit+1)]

for prime in prime_list:
    for elem in range(prime*2, max(prime_list)+1, prime):
        if elem in prime_list:
            prime_list.remove(elem)
"""   
, number=10))

1
import timeit


def oct(x):
   return x*x


timeit.Timer("for x in range(100): oct(x)", "gc.enable()").timeit()

무엇입니까 gc.enable()?
Robin Andrews

0

내장 timeit 모듈은 IPython 명령 행에서 가장 잘 작동합니다.

모듈 내에서 기능 시간을 설정하려면 :

from timeit import default_timer as timer
import sys

def timefunc(func, *args, **kwargs):
    """Time a function. 

    args:
        iterations=3

    Usage example:
        timeit(myfunc, 1, b=2)
    """
    try:
        iterations = kwargs.pop('iterations')
    except KeyError:
        iterations = 3
    elapsed = sys.maxsize
    for _ in range(iterations):
        start = timer()
        result = func(*args, **kwargs)
        elapsed = min(timer() - start, elapsed)
    print(('Best of {} {}(): {:.9f}'.format(iterations, func.__name__, elapsed)))
    return result

0

매개 변수를 허용하는 함수와 함께 Python REPL 인터프리터를 사용하는 방법의 예

>>> import timeit                                                                                         

>>> def naive_func(x):                                                                                    
...     a = 0                                                                                             
...     for i in range(a):                                                                                
...         a += i                                                                                        
...     return a                                                                                          

>>> def wrapper(func, *args, **kwargs):                                                                   
...     def wrapper():                                                                                    
...         return func(*args, **kwargs)                                                                  
...     return wrapper                                                                                    

>>> wrapped = wrapper(naive_func, 1_000)                                                                  

>>> timeit.timeit(wrapped, number=1_000_000)                                                              
0.4458435332577161                                                                                        

0

두 개의 함수를 만든 다음 이와 비슷한 것을 실행합니다. 사과와 사과를 비교하기 위해 같은 수의 실행 / 실행을 선택하려고합니다.
이것은 Python 3.7에서 테스트되었습니다.

여기에 이미지 설명을 입력하십시오 쉽게 복사 할 수있는 코드는 다음과 같습니다.

!/usr/local/bin/python3
import timeit

def fibonacci(n):
    """
    Returns the n-th Fibonacci number.
    """
    if(n == 0):
        result = 0
    elif(n == 1):
        result = 1
    else:
        result = fibonacci(n-1) + fibonacci(n-2)
    return result

if __name__ == '__main__':
    import timeit
    t1 = timeit.Timer("fibonacci(13)", "from __main__ import fibonacci")
    print("fibonacci ran:",t1.timeit(number=1000), "milliseconds")
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.