Python에서 시간측정하기

요즈음 파이썬의 내부 구조를 자세히 이해해야할 필요성을 느껴서 시간 측정을 자주 하고 있는데, 그 방법에 대해서 몇가지 정리해보았다. (고성능 파이썬이라는 책을 참고하면서 작성했다)

자주 사용해야 할 때 (decorator)

자주 사용을 해야할 때는 아무래도 최대한 간단하게 쓸 수 있도록 미리 작성해두는 편이 편하다. 그래서 위의 책에서는 decorator를 이용하기를 추천하는데, 좋은 방법이라고 생각한다.

import time

from functools import wraps

def check_time(function):
	@wraps(function)
	def measure(*args, **kwargs):
		start_time = time.time()

		result = function(*args, **kwargs)

		end_time = time.time()

		print(f"@check_time: {function.__name__} took {end_time - start_time}")
		return result

	return measure

위의 코드는 check_time이라는 decorator이고, 함수를 실행하기 전후로 시간을 측정한 뒤 그 차이값을 출력해주는 역할을 한다. 이는 아래처럼 사용이 가능하다.

@check_time
def test_function():
	for _ in range(10000):
		print("Just print something")

if __name__ == "__main__":
	test_function()

출력값은 아래처럼 나타난다.

$ python3.6 test.py
Just print something
Just print something
Just print something
Just print something
Just print something
...
@check_time: test_function took 0.03430891036987305

timeit 모듈

timeit 모듈은 짧은 코드의 실행시간을 확인해볼 수 있는 모듈이다. CLI로 실행하는 모듈이며, 아래와 같은 방법으로 간단하게 사용이 가능하다. (Python에서는 특정 모듈을 커맨드라인에서 실행할 때 -m옵션으로 실행이 가능하다.)

$ python3.6 -m timeit '[x**2 for x in range(10000)]'
100 loops, best of 3: 2.38 msec per loop
$ python3.6 -m timeit 'list(map(lambda x: x**2, range(10000)))'
100 loops, best of 3: 3.11 msec per loop

위의 코드는 0~9999까지의 숫자들의 제곱이 담긴 리스트를 만드는 코드이다. 하나는 list comprehension으로, 하나는 maplist를 이용하여 생성해내었다. (map의 결과물은 list나, dict가 아닌 iterator이다..! 1)

timeit 모듈은 물론 프로그램 코드에서도 사용이 가능하다. 하지만, 아래처럼 일시적으로 GC를 비활성화시킨다고 하므로, 실제 코드와 실행시간이 차이날 수 있음을 알 수 있다. 하지만, 아래처럼 다시 gc를 활성화 시킬수도 있다.

Note: By default, timeit() temporarily turns off garbage collection during the timing. The advantage of this approach is that it makes independent timings more comparable. This disadvantage is that GC may be an important component of the performance of the function being measured. If so, GC can be re-enabled as the first statement in the setup string. For example:

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

time 명령어

이 방법은 제일 자주 쓰는 방법인데, 커맨드 라인에서 단순히 time 명령어를 앞에 붙이는 방식이다. 아래와 같은 방식으로 사용하며, real, user, sys등 세가지의 정보를 얻을 수 있다. 대략적인 의미는 real이 경과한 총 시간, user는 커널이 아닌 코드가 소비한 시간, sys는 커널 함수 때문에 소비한 시간이다. macOS를 기준으로, -l 항목을 같이 넘겨준다면, 메모리와 관련된 자세한 결과를 받을 수 있다. (다른 OS는 --verbose를 시도해보자. 둘이 같은 기능은 아니다..)

$ time python test.py
{프로그램 출력값}

real	0m0.100s
user	0m0.032s
sys	0m0.043s

그 외에도 cProfile이라는 모듈을 이용해서 측정하는 방법이 있는데, 그 방법은 나중에 다시 정리하기로…

  1. https://docs.python.org/3/library/functions.html#map Return an iterator that applies function to every item of iterable, yielding the results. … 

February 15, 2019 에 작성
Tags: python