Cython
ことはじめ
IGGG Meetup 2015 Spring
擬音 @gion_U
お前誰よ
• 擬音 @gion_U
• 興味
• Python / Web開発
• バイトしてた
• やってること
• 研究室で MATLAB 使って線形代数こねこね
• (パターン認識・機械学習)
sucks
>> A
A =
1 2 3
4 5 6
7 8 9
>> sum(A)
ans =
12 15 18
>> sum(A, 1)
ans =
12 15 18
>> sum(A, 2)
ans =
6
15
24
>> A
A =
1 2 3
4 5 6
7 8 9
>> sum(A)
ans =
12 15 18
>> sum(A, 1)
ans =
12 15 18
>> sum(A, 2)
ans =
6
15
24
b =
1 2 3
>> A
A =
1 2 3
4 5 6
7 8 9
>> sum(A)
ans =
12 15 18
>> sum(A, 1)
ans =
12 15 18
>> sum(A, 2)
ans =
6
15
24
b =
1 2 3
>> sum(b)
ans =
6
>> A
A =
1 2 3
4 5 6
7 8 9
>> sum(A)
ans =
12 15 18
>> sum(A, 1)
ans =
12 15 18
>> sum(A, 2)
ans =
6
15
24
b =
1 2 3
>> sum(b)
ans =
6
I 💖
スクリプト言語なので、
どうしても

コンパイラ言語より遅い
I 💔
[Cython] is a programming
language that makes
writing C extensions for the
Python language as easy as
Python itself.
http://cython.org/docs/current/src/quickstart/overview.html
http://cython.org/docs/current/src/quickstart/overview.html
Python書くくらいの

気軽なノリで

C 拡張が書ける言語だよ!
特徴
• “Pythonic”
• Python コードに型情報付けた感じ
• Python 向け C 拡張ライブラリとしてビルドで
きる他に、Cython コードを実行形式バイナリ
としてビルドすることも可能
• 変数の型宣言(しなくてもよい)
• Python の型も使える
• Python っぽいコード
def newton(double init):
cdef list result = []
cdef double current = init
cdef double past = 0
while True:
past = current
current = (current + (7 / current)) / 2
if abs(current - past) < 1e-10:
break
result.append(current)
return result
if __name__ == '__main__':
print(newton(3))
CPython から使う
1. pip install cython
2. Cython コードを .pyx として保存
3. import pyximport

pyximport.install()
4. import <module_name>
5. コンパイルされる。エラーが発生しなければ成功
実行形式バイナリの生成
• 前ページの Cython コードから

次のようにして生成
% cython newton_pyx.pyx --embed
% cc -I${PYTHON_INCLUDE_DIR} -L{PYTHON_LIBRARY_DIR} 
-lpython3.4 newton_pyx.c
% ./a.out
[2.666666666666667, 2.645833333333333, 2.6457513123359577,
2.6457513110645907]
ここではやってないけれど
• 外部のソースの関数なども extern で

持ち込める
• よく使われそうな定義は予め用意されている
• CPython, C, C++, NumPy, POSIX
※ C++ コードを生成できる
cdef extern from "myfuncs.h"
double func(double x, int y)
from libc.math cimport sin
速度計測
• ハードウェア環境
• MacBook Pro Retina 13” (Mid 2013)
• Core i5, 16G RAM
• ソフトウェア環境
• Mac OS X 10.10
• Python 3.4.3 (from Homebrew [bottle])
• Cython 0.22
• Clang 3.5.1 (tags/RELEASE_351/final)
• 4 つのモジュールを作成
• newton
• 素の Python, 漸近のようすを表すリストを返す
• newton2
• 素の Python, 漸近の結果を返す
• newton_pyx
• newton2_pyx
• 上記の 2 モジュールの Cython 実装
速度計測
(ニュートン法による関数近似)
• timeit.repeat(repeat=10, ...)

の最小値
• 100 万回の実行を

10 セット行ったときの最小時間
速度計測
(ニュートン法による関数近似)
結果
結果
• Python
• newton - 2.36 sec
• newton2 - 1.83 sec
結果
• Python
• newton - 2.36 sec
• newton2 - 1.83 sec
• Cython
• newton_pyx - 0.27 sec
• newton2_pyx - 0.17 sec
Cython つよい
ところで
Python の関数
• 呼び出しに伴うコストが大きい
• 関数もオブジェクト
• ルックアップ、引数渡し、……
• ループ中で呼んだり、

再帰したりで遅くなりがち
Cython の関数定義
• Cython では、Python 関数だけでなく

C 関数も定義できる(Pythonic に!)
• C 関数は Python コードから

直接呼びだせないことに注意
• cdef キーワードで定義
• cpdef キーワードを用いると、

Python からは Python 関数を、

C からは C 関数を呼んでくれる(はず)
cpdef int tarai(int x, int y, int z):
if x <= y:
return y
else:
return tarai(
tarai(x-1, y, z),
tarai(y-1, z, x),
tarai(z-1, x, y)
)
たらい回し関数(竹内関数)
• 再帰関数
• 計算対象の数が大きくなりすぎない
• 再帰のネストが深くなりすぎない
• 関数呼び出しのベンチマークに使える
http://ja.wikipedia.org/wiki/竹内関数
検証
(たらい回し関数の呼び出し)
• 3 通りの方法で関数呼び出しの速度を検証
1. Python コードをそのまま実行
2. Cython コード(Python 関数版)を実行
3. Cython コード(C 関数版)を実行
検証
(たらい回し関数の呼び出し)
• timeit.repeat(number=1) の最小値
• 『1回実行』を 10 セット行ったときの

最小時間
• すごい時間がかかったので
結果
結果
• Python - 38.8 sec
結果
• Python - 38.8 sec
• Cython(Python func) - 21.2 sec
結果
• Python - 38.8 sec
• Cython(Python func) - 21.2 sec
• Cython(C func) - 0.558 sec (!)
• 69 times faster than Python
• 37 times faster than Cython(Python func)
まとめ
• Pythonic なコードから C/C++ ソースを

生成する Cython
• 気軽に C 拡張を書ける
• 型指定は積極的に
• 関数は極力 C 関数として定義する
• 数値演算などに威力を発揮しそう

Cython ことはじめ