파이썬 실행속도를 향상시켜보자!

kkachi·2022년 11월 15일
0

파이썬 이모저모

목록 보기
1/2
post-thumbnail

안녕하세요. 까치입니다.
오늘은 파이썬 실행속도 향상을 주제로 글을 써보려고 합니다.

Background

다들 잘 아시다시피, python은 '인터프리트 언어(interpreted language)'입니다. 즉, 컴파일러를 거쳐서 기계어로 변환되지 않고 번역기 역할(ex. cpython)을 하는 프로그램에 의해서 바로 실행되는 프로그래밍 언어입니다.

이것은 파이썬이 컴파일된 언어에 비해 훨씬 더 많은 유연성을 제공하는 이유 중 하나입니다. 그러나 이것은 또한 파이썬이 엄청나게 느린 이유이기도 합니다.

멋진 개발자들은 파이썬의 느린 속도를 해결하기 위해 아래와 같은 다양한 방법을 제시합니다.

요지는 C/C++로 프로그래밍하는 방법을 알고 있다면, C 확장 인터페이스, ctypes 모듈, cffi 라이브러리 등을 통해 파이썬 실행 속도를 높일 수 있다는 것입니다.

근데 난 C/C++를 모르는 걸...?ㅠㅠ

Numba & JIT compilation

Numba는 파이썬의 유연성을 포기하지 않고도 코드를 훨씬 빠르게 만들 수 있는 파이썬 패키지입니다. 살았다-!

Numba는 python과 numpy 코드의 하위 집합을 빠른 기계 코드로 변환하는 오픈 소스 JIT 컴파일러입니다(위키백과). JIT(Just-in-time)이라는 의미는 파이썬 코드가 실행되는 동안 런타임에 컴파일한다는 것을 뜻합니다. 그래서 C/C++ 컴파일러를 사전에 설치할 필요가 없습니다.

Install Numba

pip install numba

How to use Numba

Numba 사용법은 아주 간단합니다. 단지 작성한 함수에 데코레이터 @jit를 붙여주면 됩니다.

from numba import jit
@jit
def function(x):
    # your loop or numerically intensive computations
    return x

Options

numba는 다양한 옵션들을 제공합니다. 아래는 몇 가지 자주 쓰이는 옵션을 소개합니다. 자세한 내용은 공식문서를 참고해주세요.

  • nopython : nopython=True 이면 numba가 파이썬 인터프리터를 거치지 않고 컴파일 합니다. 때문에 numba가 이해할 수 없는 코드가 들어오면 에러를 내뱉습니다. nopython=False 이면 numba가 이해할 수 없는 코드가 들어왔을 때 그냥 파이썬 인터프리터를 작동시킵니다. 즉, numba로 인한 성능 향상은 없습니다. 일반적으로 numba에서는 nopython=True 을 추천합니다.
  • cache : cache=True 이면 numba가 함수를 부를 때마다 컴파일을 새로하지 않고 cache에서 저장합니다.
  • parallel : parallel=True 이면 함수에서 자동으로 병렬화 및 최적화를 수행하려고 시도하는 numba 변환 패스가 활성화됩니다.

Pandas

Pandas는 numpy를 기반으로 만들어진 패키지로 dataframe이라는 효율적인 자료구조를 제공합니다. numba는 numpy에 친숙하므로 이를 잘 활용하면 효율적인 결과를 얻어낼 수 있습니다.

아래는 numba의 @vectorize 데코레이터를 pandas dataframe에 적용한 사례입니다.

from numba import vectorize

def get_squared_height_without_numba(height):
  return height ** 2

@vectorize
def get_squared_height_with_numba(height):
  return height ** 2


%timeit df['height'].apply(get_squared_height_without_numba)
# 279 ms ± 7.31 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


%timeit df['height'] ** 2
# 2.04 ms ± 229 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# We convert the column to a numpy array first
# since numba is compatible with numpy ( not pandas )
%timeit get_squared_height_with_numba(df['height'].to_numpy())
# 1.6 ms ± 51.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

참고링크

0개의 댓글