coLinux日記

coLinuxはフリーソフトを種として、よろずのシステムとぞなれりける。

Python 3.13.1 で、試しに Cython を使って見る。

2025-01-07 15:40:40 | Python
以前の記事、
https://blog.goo.ne.jp/espiya/e/cf058105a1d29877e483a3bd007b4039

では、インストールした Python 3.13 に Cython をインストールしておきました。Papsberry Pi は遅いので Cython の様な高速化は魅力的です。

Welcome to Cython's Developmentation
https://cython.readthedocs.io/en/stable/index.html

そこで、年末年始の隙間時間を利用して、前回インストールした Cython を使って見ます。
全く使ったことがないので、とりあえず次のものに出ていたプログラムを使います。

Faster code via static typing
https://cython.readthedocs.io/en/latest/src/quickstart/cythonize.html

このページでは、Pure Python と Cython の変更点がわかるようになっています。Pythonは変数の値の型が決まっていないので型変換に時間がかかるという考えから、Cython では型定義をするのが重要な変更点みたいです。

さて、この中の、integrate.py を Cython プログラムに変形したものが integrate_cy.pyx です。
関数の引数はそのまま型定義ができて、内部変数は cdef で定義するのですね。それ以外は変更していません。

$ cat integrate.py
def f(x):
   return x ** 2 - x

def integrate_f(a, b, N):
   s = 0
   dx = (b - a) / N
   for i in range(N):
     s += f(a + i * dx)
   return s * dx
$

$ cat integrate_cy.pyx
def f(double x):
   return x ** 2 - x

def integrate_f(double a, double b, int N):
   cdef int i
   cdef double s
   cdef double dx

   s = 0
   dx = (b - a) / N
   for i in range(N):
     s += f(a + i * dx)
   return s * dx
$


次にコンパイル?するために、setup.py を作ります。色々な所を参考にして適当に作りました。

$ cat setup.py
from distutils.core import setup, Extension
from Cython.Build import cythonize

ext = Extension("integrate", sources=["integrate_cy.pyx"], include_dirs=['.'])
setup(name="integrate", ext_modules=cythonize([ext]))

$

コンパイルします。
$ python3 setup.py build_ext --inplace
省略
$

これによって、

./build/
integrate.cpython-313-aarch64-linux-gnu.so
integrate_cy.c


が作成されました。ディレクトリ build の中身は以下の通りです。

$ ls -R build
build:
lib.linux-aarch64-cpython-313 temp.linux-aarch64-cpython-313

build/lib.linux-aarch64-cpython-313:
integrate.cpython-313-aarch64-linux-gnu.so

build/temp.linux-aarch64-cpython-313:
integrate_cy.o

$

Cython で作成されたライブラリ integrate を使って、以下のプログラム test001.py を動かすことができます。

$ cat test001.py
from integrate import f, integrate_f

if __name__ == "__main__":
   result = integrate_f(0.0, 2.0, 2000000)
   print(result)
$


比較用に、Pythonのプログラム test002.py も用意します。integrate.py の2つの関数を陽に定義しておきました。

$ cat test002.py
def f(x):
   return x ** 2 - x

def integrate_f(a, b, N):
   s = 0
   dx = (b - a) / N
   for i in range(N):
     s += f(a + i * dx)
   return s * dx

result = integrate_f(0.0, 2.0, 2000000)
print(result)
$

2つを実行して速度を比較します。

$ time python3 test001.py
0.6666656666670076

real 0m0.556s
user 0m0.543s
sys 0m0.012s

$ time python3 test002.py
0.6666656666670076

real 0m1.136s
user 0m1.128s
sys 0m0.009s
$


実際に2倍少し早くなっていますね。

今回とりあえず Cython を使ってみました。
必要な修正もあまりないので有用そうなので今後ももう少し調べてみたいと思います。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする