cProfile을 활용해서 ListComprehension의 효율성을 측정해보기

cProfile

파이썬 내장함수로 존재하는 cProfile은 CSI처럼 파이썬 코드에 작성된 '함수'를 추적하는 '함수'입니다.

사용법은 간단합니다.

# import 하신 후에
import cProfile 
# 테스팅할 함수를 작성하고
def test_cProfile(a):
    return a+10
    
# cProfile.run([함수명]) 형식으로 함수를 실행시킵니다.
cProfile.run('test_cProfile(10)')

# 결과
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 craw.py:64(test_cProfile)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

결과에 나온 항목을 뜯어봅시다.

ncalls(호출횟수)

  • 함수가 몇 번 호출되었는지 카운트 한 횟수

tottime(총시간)

  • 주어진 함수에서 소비된 총 시간(서브 함수 호출에 든 시간은 제외됩니다)

cumtime(누적시간)

  • 이 함수와 모든 서브함수에서 소요된 누적시간(호출에서 종료까지)

percall(시간 별 호출수)

  • 호출횟수 / 총시간 결과값

filename:lineno(function):

  • 각 함수의 해당 데이터(파일명: 줄 번호(함수))

ListComprehension vs ListAppend

리스트컴프리헨션과 리스트어펜드를 cProfile을 사용해 비교해봅시다.
range를 활용해 1억번 연산을 해봅시다.

소스코드

def test_list_comprehension(x):
    result = [i for i in range(x)]
    return result


def test_list_append(x):
    result = []
    for i in range(x):
        result.append(i)
    return result

cProfile.run('test_list_comprehension(100000000)')
cProfile.run('test_list_append(100000000)')

결과

5 function calls in 9.635 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    3.308    3.308    9.635    9.635 <string>:1(<module>)
        1    0.000    0.000    6.327    6.327 craw.py:64(test_list_comprehension)
        1    6.327    6.327    6.327    6.327 craw.py:65(<listcomp>)
        1    0.000    0.000    9.635    9.635 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


100000004 function calls in 22.610 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    3.184    3.184   22.609   22.609 <string>:1(<module>)
        1   13.143   13.143   19.426   19.426 craw.py:69(test_list_append)
        1    0.000    0.000   22.610   22.610 {built-in method builtins.exec}
100000000    6.283    0.000    6.283    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

9초 vs 22초로 리스트 컴프리헨션의 압승으로 나왔습니다.
결정적인 포인트는 함수 호출횟수입니다. 컴프리헨션 함수를 딱 한번 사용하는 리스트 컴프리헨션 표현식과 달리 append방식은 append내장함수를 1억번이나 호출했고 이에따라 2.5배 가까이 느리게 리스트가 생성되었습니다.

파이썬에선 왜 Pythonic하게 코드를 작성해야되는지, 대표적인 Pythonic한 Expression인 ListComprehension의 효율성을 통해 알아 볼 수 있었습니다.

좋은 웹페이지 즐겨찾기