目次
- 目次
- はじめに
- Cythonとは?
- 言語としてのcython
- cythonの使い方
- pydファイル
- Cythonの基本的な使い方
- Cythonの注意点
- 参考資料
- MyEnigma Supporters
はじめに
Pythonは、非常に沢山のライブラリが存在し、
プログラミング初心者でも簡単にコードを書くことができることから、
非常に利用が広がっていますが、
処理速度が遅いという欠点があります。
この問題を解決する方法の一つとして、
処理のボトルネックになっている部分を、
C言語などのコンパイル言語を使うことで、
高速化する方法がありますが、
そのように、既存のC言語のコードとPythonを連携させたり、
Pythonのコードに少し型情報などを追加することで、
高速化することができるのが、Cythonです。
今回の記事では、Cythonの概要と簡単な使い方を紹介したいと思います。
Cythonとは?
cythonのPythonのスーパセットである言語と、
その言語で書かれたコードから、
c言語のコードを生成するトランスパイラのことを指します。
Cythonは通常のpipを使って、インストールすることができます。
$ pip install Cython
現在は0.x系が安定版ですが、次の世代として、3.x系が開発中です。
言語としてのcython
cythonはpythonにC言語の型を追加したものであると言えます。
これにより、通常のPythonよりも高速な計算が可能になります。
また、前述の通り、cythonはpythonのスーパーセットの言語なので、
いくつかのlimitationはありますが、通常のPythonコードもコンパイルできます。
cythonの使い方
cythonには二つの大きな用途があります。
既存のPythonコードを高速化する
外部のC言語のライブラリとPythonのコードを繋ぐ
cythonコードのビルドフロー
最もシンプルなCythonコードのビルドのフローは下記の通りです。
cythonで書かれたコード .pyxを準備
cythonで.pyxコードをコンパイルして、cコードを生成する。
cコードをコンパイルして、.soか.pydにして、pythonからインポートできるようにする。
2と3のステップは、下記のような方法があります。
setup.pyで設定する
pyximportを使う
cythonのコマンドラインツールでコンパイルする
jupyterノートブックで、%load_ext Cythonと%%cythonマクロを使う
例えば、setup.pyを使う場合、下記のようなsetup.pyを準備し、
## python3 setup.py build_ext --inplace from distutils.core import setup from Cython.Build import cythonize setup(ext_modules=cythonize("*.pyx"))
setup.pyがあるディレクトリで、最初のコメントにあるコマンドを実行すると、
$ python3 setup.py build_ext --inplace
下記のように、Cythonで生成されたCコードと、
そのCコードを各プラットフォームに毎にコンパイルした、
soファイルファイルが生成されます。
あとは、上記のsoファイルと同じディレクトリにある
Pythonコードは
from primes_listc
で使えます。
pydファイル
*.pydファイルはcythonにおける、Cのヘッダーファイルのようなものです。
用途としては、
外部のCコードとのインターフェイスを定義
インライン関数の定義
複数のcythonモジュール間のデータのやり取りを定義
で利用できます。
例えば、下記のようにSciPyはCythonのPublic APIを公開しており、
直接、ユーザのCythonコードから、
SciPyのこれらのAPIを利用することができます。
Cythonの基本的な使い方
CythonはPythonのスーパーセットですので、
なんのコード変更もしなくても、コンパイルできますが、
下記のように追加で型情報を付加したり、
C/C++の機能を使ったりできます。
関数の引数や返値に型を付ける
下記のように、関数の引数に型を付けるには、
Cのように型情報を追加するだけです。
def sum(int x):
また返値の型も指定する場合は、
defをcdefに変えて、型情報を追加します。
cdef int sum(int x):
またinlineをつけることで、関数のインライン化も可能です。
変数に型を付ける
変数に型を付けるときは、cdef のあとに型情報を付けます
cdef int i cdef int n = 2, p cdef long sum cdef int[:,:] counts # 二次元配列
また、cdefでブロックを作ると、毎回cdefを書かなくても良くなります。
cdef: int i int n = 2, p long sum
C/C++のvectorを使う
C言語のarrayは下記のように使えます。
cdef int[100] x
C++のstdvectorも使えます。
C++のライブラリを使う場合は、
下記のように、まず最初の行にC++を使うことを宣言し、
CythonのトランスパイラにC++コードを使うことを認識させて、
あとはvectorをインポートして使うだけです。
普通にpush_backが使えます。
# distutils: language=c++ from libcpp.vector cimport vector cdef vector[int] vec vec.reserve(100) # preallocation for i in range(100) p_vector.push_back(i)
配列の境界チェックや負のインデックスアクセスをオフにして高速化する
pyxのコードの先頭にこのコメントを書くと、Cの配列と同様に、
配列の境界チェックや負のインデックスアクセスがオフされ、高速化されます。
# cython: boundscheck=False, wraparound=False
並列処理をする
Cythonを使うとOpenMPを使った並列処理も実現できます。
まず、OpenMPをCythonで使うには、このコメントを追加します。
# distutils: extra_compile_args = -fopenmp # distutils: extra_link_args = -fopenmp
これで、関数の後ろにnogilとつけると、
GIL (Global Interpreter Lock)をオフできるようになったり、
cython.parallelのprangeや、parallelで並列処理ができるようになります。
Cythonの注意点
Cythonを使う場合は下記の項目に注意したほうが良いようです。
必ずしもPython版より高速になるわけではない。(ちゃんとプロファイルを取る)
例外は使えない (返り値で判断する)
参考資料
MyEnigma Supporters
もしこの記事が参考になり、
ブログをサポートしたいと思われた方は、
こちらからよろしくお願いします。