概略
numbaとは,JIT(just-in-time)コンパイラを使ってPythonを動作させるモジュール,
Cythonとは,Pythonみたいに書けるけどC/C++と同様に事前コンパイルするプログラミング言語です.
とりあえず動かしてみる
以下,Jupyter Notebook上での処理になります.
Anaconda, python 3.7.3 を使用.
フィボナッチ数列のn番目を生成するコードで,python, numba, cython, 型指定つきcython, の4つで速度比較をしてみます.
まずは普通のpython
def python_fib(n):
a, b = 0., 1.
for i in range(n):
a, b = a + b, a
return a
timeit
モジュールで,フィボナッチ数列の1000番目の数を計算する処理にかかる時間を計測してみます.
%timeit python_fib(1000)
10000 loops, best of 3: 33.6 µs per loop
平均して 33.6マイクロ秒かかったようです.
この場合、コマンド %timeit は以下の処理を行っています.
- python_fib(1000)を10000回実行し、総実行時間を保存.
- python_fib(1000)を10000回実行し、総実行時間を保存.
- python_fib(1000)を10000回実行し、総実行時間を保存.
- 3回実行した中で最も短い実行時間を取得し、それを10000で割った値を、10000の最短実行時間として出力。
ループ回数(ここでは10000ループ)は、%timeit
の機能によって自動調整されており,測定するコードの実行速度に応じて変化します.
Numbaでコンパイルした場合
numbaはpip
でインストールできます.
pip install numba
numbaの使い方は非常に簡単で,@jit
デコレータをつけるだけです.
from numba import jit
@jit
def numba_fib(n):
a, b = 0.0, 1.0
for i in range(n):
a, b = a + b, a
return a
処理時間を計測します.
%timeit numba_fib(1000)
The slowest run took 77684.24 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.26 µs per loop
1.26マイクロ秒!26倍もの高速化になりました.
Cython を使用した場合
jupyterでは,以下のマジックコマンドでcythonがロードできます.
%load_ext Cython
%%cython を最初に入れることで,コンパイルと最適化が行われます.
%%cython
def cython_fib(n):
a, b = 0.0, 1.0
for i in range(n):
a, b = a + b, a
return a
%timeit cython_fib(1000)
100000 loops, best of 3: 8.22 µs per loop
8.22マイクロ秒.何もしなくても4倍程度には速くなりましたね.
最後に,型指定をした後に,cythonでコンパイルした場合.
%%cython
def cython_fib2(int n):
a, b = 0., 1.
for i in range(n):
a, b = a + b, a
return a
%timeit cython_fib2(1000)
The slowest run took 7.27 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 984 ns per loop
0.984マイクロ秒!34倍も早くなりました.
最後に
上のような簡単な処理なら,numbaやcythonで動かすことは容易ですが,複雑な処理になると対応できないケースがでてきます.
速度を求める場合には早めに別言語に切り替えたり,マルチプロセスやハードウェア選定から検討したほうがいいかもしれません.