programing tip

파이썬에서 정확한 함수 타이밍

itbloger 2020. 11. 26. 07:59
반응형

파이썬에서 정확한 함수 타이밍


Windows에서 Python으로 프로그래밍 중이며 함수가 실행되는 데 걸리는 시간을 정확하게 측정하고 싶습니다. 다른 함수를 사용하여 실행하고 실행하는 데 걸린 시간을 반환하는 "time_it"함수를 작성했습니다.

def time_it(f, *args):
    start = time.clock()
    f(*args)
    return (time.clock() - start)*1000

나는 이것을 1000 번 호출하고 결과를 평균화합니다. (끝의 1000 상수는 밀리 초 단위로 답을 제공하는 것입니다.)

이 기능은 작동하는 것처럼 보이지만 내가 뭔가 잘못하고 있다는 잔소리가 들며, 이런 식으로 수행하면 기능이 실행될 때 실제로 사용하는 것보다 더 많은 시간을 사용하고 있습니다.

이를 수행하는 더 표준 또는 승인 된 방법이 있습니까?

더 오래 걸리도록 테스트 함수를 변경하여 인쇄를 호출하면 time_it 함수는 평균 2.5ms를 반환하고 cProfile.run ( 'f ()')은 평균 7.0ms를 반환합니다. 내 기능이 시간을 과대 평가할 것이라고 생각했습니다. 여기서 무슨 일이 일어나고 있습니까?

한 가지 추가 참고 사항은 하드웨어 및 기타 요인에 따라 분명히 달라질 수 있으므로 절대 시간이 아니라 내가 관심을 갖는 서로 비교 한 기능의 상대적 시간입니다.


고유 한 프로파일 링 코드를 작성하는 대신 내장 Python 프로파일 러 ( profile또는 cProfile필요에 따라) 를 확인하는 것이 좋습니다 . http://docs.python.org/library/profile.html


Python 표준 라이브러리 timeit모듈사용합니다 .

기본 사용법 :

from timeit import Timer

# first argument is the code to be run, the second "setup" argument is only run once,
# and it not included in the execution time.
t = Timer("""x.index(123)""", setup="""x = range(1000)""")

print t.timeit() # prints float, for example 5.8254
# ..or..
print t.timeit(1000) # repeat 1000 times instead of the default 1million

다음과 같이 "timeme"데코레이터를 만들 수 있습니다.

import time                                                

def timeme(method):
    def wrapper(*args, **kw):
        startTime = int(round(time.time() * 1000))
        result = method(*args, **kw)
        endTime = int(round(time.time() * 1000))

        print(endTime - startTime,'ms')
        return result

    return wrapper

@timeme
def func1(a,b,c = 'c',sleep = 1):
    time.sleep(sleep)
    print(a,b,c)

func1('a','b','c',0)
func1('a','b','c',0.5)
func1('a','b','c',0.6)
func1('a','b','c',1)

이 코드는 매우 정확하지 않습니다.

total= 0
for i in range(1000):
    start= time.clock()
    function()
    end= time.clock()
    total += end-start
time= total/1000

이 코드는 덜 정확합니다.

start= time.clock()
for i in range(1000):
    function()
end= time.clock()
time= (end-start)/1000

함수의 런타임이 클록의 정확도에 가까우면 매우 부정확 한 경우 측정 바이어스가 발생합니다. 대부분의 측정 된 시간은 시계의 0에서 몇 틱 사이의 난수 일뿐입니다.

시스템 워크로드에 따라 단일 기능에서 관찰하는 "시간"은 전적으로 OS 스케줄링 및 기타 제어 할 수없는 오버 헤드의 아티팩트 일 수 있습니다.

두 번째 버전 (덜 부정확 함)은 측정 편향이 적습니다. 함수가 정말 빠르다면 OS 스케줄링 및 기타 오버 헤드를 줄이기 위해 10,000 번 실행해야 할 수도 있습니다.

물론 둘 다 끔찍하게 오해의 소지가 있습니다. 전체적으로 프로그램의 실행 시간은 함수 실행 시간의 합계가 아닙니다. 상대 비교를 위해서만 숫자를 사용할 수 있습니다. 많은 의미를 전달하는 절대적인 측정치가 아닙니다.


If you want to time a python method even if block you measure may throw, one good approach is to use with statement. Define some Timer class as

import time

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self

    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

Then you may want to time a connection method that may throw. Use

import httplib

with Timer() as t:
    conn = httplib.HTTPConnection('google.com')
    conn.request('GET', '/')

print('Request took %.03f sec.' % t.interval)

__exit()__ method will be called even if the connection request thows. More precisely, you'd have you use try finally to see the result in case it throws, as with

try:
    with Timer() as t:
        conn = httplib.HTTPConnection('google.com')
        conn.request('GET', '/')
finally:
    print('Request took %.03f sec.' % t.interval)

More details here.


This is neater

from contextlib import contextmanager

import time
@contextmanager
def timeblock(label):
    start = time.clock()
    try:
        yield
    finally:
        end = time.clock()
        print ('{} : {}'.format(label, end - start))



with timeblock("just a test"):
            print "yippee"

Similar to @AlexMartelli's answer

import timeit
timeit.timeit(fun, number=10000)

can do the trick.

참고URL : https://stackoverflow.com/questions/889900/accurate-timing-of-functions-in-python

반응형