Pythons timeit로 성능을 테스트하기 위해 코드 세그먼트의 시간을 어떻게 정할 수 있습니까?


162

파이썬 스크립트는 정상적으로 작동하지만 실행 시간을 작성해야합니다. 사용해야한다고 Google에서 확인 timeit했지만 작동하지 않는 것 같습니다.

내 파이썬 스크립트는 다음과 같습니다

import sys
import getopt
import timeit
import random
import os
import re
import ibm_db
import time
from string import maketrans
myfile = open("results_update.txt", "a")

for r in range(100):
    rannumber = random.randint(0, 100)

    update = "update TABLE set val = %i where MyCount >= '2010' and MyCount < '2012' and number = '250'" % rannumber
    #print rannumber

    conn = ibm_db.pconnect("dsn=myDB","usrname","secretPWD")

for r in range(5):
    print "Run %s\n" % r        
    ibm_db.execute(query_stmt)
 query_stmt = ibm_db.prepare(conn, update)

myfile.close()
ibm_db.close(conn)

내가 필요한 것은 쿼리를 실행하고 파일에 쓰는 데 걸리는 시간 results_update.txt입니다. 목적은 다른 인덱스 및 조정 메커니즘으로 데이터베이스에 대한 업데이트 명령문을 테스트하는 것입니다.


귀하의 질문에 대해 구체적 timeit입니까? 나는 그렇지 않다고 생각한다. 이 경우 제목에서 "with Pythons timeit"을 제거해야합니다.
Martin Thoma

답변:


275

당신은 사용할 수 있습니다 time.time()또는 time.clock()전에 당신이 시간에 원하는 블록 후.

import time

t0 = time.time()
code_block
t1 = time.time()

total = t1-t0

이 방법은 정확 timeit하지는 않지만 (몇 번의 실행을 평균하지는 않음) 간단합니다.

time.time()(Windows 및 Linux) 및 time.clock()(Linux)는 빠른 기능을 위해 충분히 정확하지 않습니다 (총 = 0을 얻음). 이 경우 또는 여러 번의 실행으로 경과 된 시간의 평균을 계산하려면 함수를 여러 번 수동으로 호출해야합니다 (이미 예제에서 수행 한 것처럼 숫자 인수 를 설정하면 timeit가 자동으로 수행됩니다 )

import time

def myfast():
   code

n = 10000
t0 = time.time()
for i in range(n): myfast()
t1 = time.time()

total_n = t1-t0

Windows에서 Corey는 의견에서 언급했듯이 time.clock()훨씬 높은 정밀도 (초 대신 마이크로 초)를 가지며보다 선호됩니다 time.time().


8
Windows에서는 f. time.time () 대신 time.clock ()을 사용하십시오.
Corey Goldberg

4
고마워 코리 왜? 시계가 더 정확하거나 (마이크로 초) 더 많은 것이 있기 때문에?
joaquin

11
timeit.default_timer ()를 사용하여 코드 플랫폼을 독립적으로 만들 수 있습니다. OS에 따라 time.clock () 또는 time.time ()을 반환합니다.
Marc Stober

6
손으로 시계를 선택하지 말고 timeit.default_timer; 파이썬은 이미 당신을 위해 일을했습니다. 그러나 실제로 timeit.timeit(myfast, number=n)반복적 인 호출 휠을 다시 발명하는 대신 사용해야 합니다 ( timeit코드를 반복적으로 실행하는 동안 가비지 수집기 를 비활성화하는 사실을 놓치지 마십시오 ).
Martijn Pieters

15
업데이트 : time.clock ()은 더 이상 사용되지 않습니다. 이제 time.time ()을 사용해야합니다. 실제로, 버전 3.3 이후로 가장 좋은 옵션은 time.perf_counter ()
Madlozoz

42

코드를 프로파일 링하고 IPython을 사용할 수있는 경우 매직 기능이 %timeit있습니다.

%%timeit 세포에서 작동합니다.

In [2]: %timeit cos(3.14)
10000000 loops, best of 3: 160 ns per loop

In [3]: %%timeit
   ...: cos(3.14)
   ...: x = 2 + 3
   ...: 
10000000 loops, best of 3: 196 ns per loop

36

타이밍과는 별도로,이 코드는 잘못되었습니다 .100 개의 연결을 실행하고 (마지막을 제외한 모든 연결을 완전히 무시) 첫 번째 실행 호출을 수행하면 로컬 변수 query_stmt를 전달 하여 실행 후에 만 초기화 합니다 요구.

먼저 타이밍에 대해 걱정하지 않고 코드를 올바르게 작성하십시오. 즉, 연결을 작성 또는 수신하고 100 또는 500 또는 해당 연결에서 업데이트 횟수를 수행 한 다음 연결을 닫는 기능입니다. 코드가 올바르게 작동하면 코드 사용에 대한 올바른 생각입니다 timeit!

특히, 시간을 정하려 는 함수가 매개 변수가없는 foobar경우 timeit.timeit (2.6 이상-2.5 이전에는 더 복잡 합니다)를 사용할 수 있습니다 .

timeit.timeit('foobar()', number=1000)

사용 횟수에 대한 기본값 인 백만 개가 높을 수 있으므로 실행 횟수를 지정하는 것이 좋습니다 (이 코드에서 많은 시간을 소비합니다 ;-).


26
마지막 몇 분 동안이 문제를 해결 한 후 장래 시청자에게 함수 foobar가 기본 파일에 있으면 설정 변수를 전달하고 싶다는 것을 알리고 싶습니다 . : 이것처럼 timeit.timeit('foobar()','from __main__ import foobar',number=1000)
리치

3
Python 2.7.8에서는 다음과 같이 간단하게 사용할 수 있습니다timeit.timeit( foobar, number=1000 )

9

하나의 특정한 것에 집중하십시오 . 디스크 I / O가 느리기 때문에 데이터베이스 쿼리 만 조정하면 테스트에서 제외됩니다.

또한 데이터베이스 실행 시간을 정해야하는 경우 쿼리 계획을 요청하는 등의 데이터베이스 도구를 찾아보고 정확한 쿼리와 사용하는 인덱스뿐만 아니라 데이터로드 (데이터 양에 따라 다름)에 유의하십시오. 저장했습니다).

즉, 단순히 코드를 함수에 넣고 다음을 사용하여 해당 함수를 실행할 수 있습니다 timeit.timeit().

def function_to_repeat():
    # ...

duration = timeit.timeit(function_to_repeat, number=1000)

이렇게하면 가비지 수집이 비활성화되고 function_to_repeat()함수가 반복적으로 호출 되며을 사용하여 해당 호출의 총 지속 시간이 timeit.default_timer()지정됩니다. 이는 특정 플랫폼에 가장 정확한 시계입니다.

당신은 설정 코드를 이동해야 밖으로 반복 기능; 예를 들어, 먼저 데이터베이스에 연결 한 다음 쿼리 만 시간 지정해야합니다. setup인수를 사용하여 해당 종속성을 가져 오거나 작성하고 함수에 전달하십시오.

def function_to_repeat(var1, var2):
    # ...

duration = timeit.timeit(
    'function_to_repeat(var1, var2)',
    'from __main__ import function_to_repeat, var1, var2', 
    number=1000)

전역을 잡아 것 function_to_repeat, var1그리고 var2당신의 스크립트 및 함수를 각각의 반복에 사람들을 전달합니다.


코드를 함수에 넣는 것은 단순히 코드를 문자열로 만들고 evaling이 완전히 사소하지 않은 것을 위해 날지 않을 것이기 때문에 찾고있는 단계 입니다. thx
javadba

2

나는 그 질문에 이미 답을 보았지만 여전히 2 센트를 더하고 싶습니다.

또한 여러 가지 접근 방식의 실행 시간을 테스트 해야하는 작은 시나리오를 작성했으며 작은 스크립트를 작성하여 작성된 모든 함수에 대해 timeit을 호출했습니다.

스크립트는 또한 github의의 요지로 사용할 수 있습니다 여기에 .

그것이 당신과 다른 사람들을 도울 수 있기를 바랍니다.

from random import random
import types

def list_without_comprehension():
    l = []
    for i in xrange(1000):
        l.append(int(random()*100 % 100))
    return l

def list_with_comprehension():
    # 1K random numbers between 0 to 100
    l = [int(random()*100 % 100) for _ in xrange(1000)]
    return l


# operations on list_without_comprehension
def sort_list_without_comprehension():
    list_without_comprehension().sort()

def reverse_sort_list_without_comprehension():
    list_without_comprehension().sort(reverse=True)

def sorted_list_without_comprehension():
    sorted(list_without_comprehension())


# operations on list_with_comprehension
def sort_list_with_comprehension():
    list_with_comprehension().sort()

def reverse_sort_list_with_comprehension():
    list_with_comprehension().sort(reverse=True)

def sorted_list_with_comprehension():
    sorted(list_with_comprehension())


def main():
    objs = globals()
    funcs = []
    f = open("timeit_demo.sh", "w+")

    for objname in objs:
        if objname != 'main' and type(objs[objname]) == types.FunctionType:
            funcs.append(objname)
    funcs.sort()
    for func in funcs:
        f.write('''echo "Timing: %(funcname)s"
python -m timeit "import timeit_demo; timeit_demo.%(funcname)s();"\n\n
echo "------------------------------------------------------------"
''' % dict(
                funcname = func,
                )
            )

    f.close()

if __name__ == "__main__":
    main()

    from os import system

    #Works only for *nix platforms
    system("/bin/bash timeit_demo.sh")

    #un-comment below for windows
    #system("cmd timeit_demo.sh")

2

다음은 스티븐의 답변에 대한 간단한 래퍼입니다. 이 기능은 반복적 인 실행 / 평균화를 수행하지 않으며, 언제 어디서나 타이밍 코드를 반복하지 않아도됩니다. :)

'''function which prints the wall time it takes to execute the given command'''
def time_func(func, *args): #*args can take 0 or more 
  import time
  start_time = time.time()
  func(*args)
  end_time = time.time()
  print("it took this long to run: {}".format(end_time-start_time))

0

테스트 스위트는 가져온 timeit것을 사용하려고 시도하지 않으므로 의도가 무엇인지 말하기가 어렵습니다. 그럼에도 불구하고 이것은 정식 답변이므로 Martijn의 답변을timeit 자세히 설명 하는 완전한 예가 순서대로 보입니다 .

에 대한 문서timeit 제공하는 많은 예제와 플래그의 가치가 체크 아웃. 명령 행의 기본 사용법은 다음과 같습니다.

$ python -mtimeit "all(True for _ in range(1000))"
2000 loops, best of 5: 161 usec per loop
$ python -mtimeit "all([True for _ in range(1000)])"
2000 loops, best of 5: 116 usec per loop

-h모든 옵션을 보려면 다음을 실행 하십시오. Python MOTW 에는 timeit명령 행에서 가져 오기 및 여러 줄 코드 문자열을 통해 모듈을 실행하는 방법을 보여주는 훌륭한 섹션이 있습니다.

스크립트 형식에서는 일반적으로 다음과 같이 사용합니다.

import argparse
import copy
import dis
import inspect
import random
import sys
import timeit

def test_slice(L):
    L[:]

def test_copy(L):
    L.copy()

def test_deepcopy(L):
    copy.deepcopy(L)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--n", type=int, default=10 ** 5)
    parser.add_argument("--trials", type=int, default=100)
    parser.add_argument("--dis", action="store_true")
    args = parser.parse_args()
    n = args.n
    trials = args.trials
    namespace = dict(L = random.sample(range(n), k=n))
    funcs_to_test = [x for x in locals().values() 
                     if callable(x) and x.__module__ == __name__]
    print(f"{'-' * 30}\nn = {n}, {trials} trials\n{'-' * 30}\n")

    for func in funcs_to_test:
        fname = func.__name__
        fargs = ", ".join(inspect.signature(func).parameters)
        stmt = f"{fname}({fargs})"
        setup = f"from __main__ import {fname}"
        time = timeit.timeit(stmt, setup, number=trials, globals=namespace)
        print(inspect.getsource(globals().get(fname)))

        if args.dis:
            dis.dis(globals().get(fname))

        print(f"time (s) => {time}\n{'-' * 30}\n")

필요한 함수와 인수를 쉽게 넣을 수 있습니다. 부적절한 기능을 사용할 때는주의를 기울이고 상태를 관리하십시오.

샘플 출력 :

$ python benchmark.py --n 10000
------------------------------
n = 10000, 100 trials
------------------------------

def test_slice(L):
    L[:]

time (s) => 0.015502399999999972
------------------------------

def test_copy(L):
    L.copy()

time (s) => 0.01651419999999998
------------------------------

def test_deepcopy(L):
    copy.deepcopy(L)

time (s) => 2.136012
------------------------------

0

또 다른 간단한 timeit 예 :

def your_function_to_test():
   # do some stuff...

time_to_run_100_times = timeit.timeit(lambda: your_function_to_test, number=100)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.