Pythonを高速化しよう!
はじめまして、gumiの津村です。
現在は解析系の仕事をしたり、ツールを作ったりしています。
今回の話は高速化についてです。
結構長めの文章です。
実行速度の高速化
高速化といっても色々ありますが、今回は実行速度の高速化についてです。
弊社ではPythonを全面的に採用していますが、そもそもLLは実行速度が遅い言語です。特にC言語のようなコンパイラ系の言語と比べると非常に遅いです。
それでもLL系の言語がここまで使われるようになったのは、開発効率が良いからです。
もはや常識ですね。
しかし、それでも特定の領域ではどうしてもPythonのようなLL系言語では厳しい部分も出てきます。
アルゴリズムを変更しても、ハードウエアを変えても、無理な物は無理です。
速度に問題がある場合の最適化にはいくつかのアプローチがあります。
- アルゴリズムの最適化により実行速度をあげる。
- 現実的に考えて実装、運用が無理な機能は、運用でカバーする。
- 言語を変える。例えばPythonからC言語に変える等。
- C/C++でライブラリ作成を行い高速化する。またはそれに伴う各関連技術を使用する。
今回の内容は最後のパターンが話の中心となります。
Python/C API
これはPythonが提供しているアプリケーションプログラマ用インタフェースです。
日本語のドキュメントはここから見ることが出来ます。
ソースコード
簡単なプログラムを作ってみましょう。
基本は"Hello World"ですよね。
/* hello.c */ #include "Python.h" static PyObject * hello(PyObject *self) { printf("Hello World!!\n"); Py_RETURN_NONE; } static char hello_doc[] = "hello module\n"; static PyMethodDef methods[] = { {"hello", (PyCFunction)hello, METH_NOARGS, "print hello world.\n"}, {NULL, NULL, 0, NULL} }; void inithello(void) { Py_InitModule3("hello", methods, hello_doc); }
ctypes
2.5以上ではctypesというモジュールを使用すると、Cのライブラリを読み込み使用する事が出来ます。
ソースコード
さきほどと同じくHello Worldを作成してみます。
/* hello.c */ #include <stdio.h> void hello(void) { printf("Hello World!\n"); }
コンパイル && 実行
単なる共有ライブラリを作るのと同じ方法です。
$ gcc -Wall -fPIC -c hello.c $ gcc -shared -o hello.so hello.o
#hello.py import ctypes hello = ctypes.cdll.LoadLibrary('hello.so') hello.hello() #=>Hello World!
利点、欠点
ctypesの利点、欠点を挙げておきましょう
利点
- Pythonに標準でついてくる。これは非常に大きな利点です。追加のライブラリが必要ないからです。
- Python/C APIとは異なり、特殊な知識は必要はありません。もちろんコンパイラやライブラリ関係の知識は必要ですが...
- 構造体を含めて、Cの型をそのまま扱えます
- マルチOS対応。Windows、Linuxでも動作するとのことです。私の環境のMac OSXでも動作は確認しています
- ソースコードはPythonのみで完結します
欠点
- マルチOS対応のプログラムを書く必要がある場合には、LoadLibrary()の部分をPython側でその対応が必要になります
- 当然、マルチOS対応が難しくなります
- ソースコードはPythonのみで完結する代わり、本来ならば隠蔽すべきローレベルの部分が丸見えになります
- ソースコードが煩雑になりがちです
ちょっとしたCの関数を呼びたい時に利用するのが良い使い方ではないか、と感じます。
ただし、大規模開発には向かないかなと感じました。
Pyrex
Python/C APIの欠点として拡張モジュールを書くのにはそれなりにCプログラミングの経験が要求されることです。
PyrexはPythonに似た文法ですので、簡単に拡張モジュールが作成できます。
Pyrexの情報はここを参照してください。
インストール
弊社ではvirtualenvを使用していますのでpipでインストールします。virtualenvを使用していな場合はeasy_installでインストールできます。
$ pip install pyrex $ easy_install pyrex
ソースコード
Hello World程度ならば普通のPythonと代わりがありません。
ちなみに拡張子は".pyx"を使用します。
#hello.pyx def hello(): print "Hello World!!"
Cython
CythonはPyrexから派生したものです。Pythonと上位互換があります。
インストール
Pyrexと同じくCythonのインストールを事前に行います。
$ pip install cython $ easy_install cython
ソースコード
Hello World程度ならばPyrexと変わりがありません。
拡張子はPyrexと同じく".pyx"を使用します。
#hello.pyx def hello(): print "Hello World!!"
CythonがPyrexと異なるのはコンパイルの為に「setup.py」が必要な事です。
#setup.py from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext hello_modules = [Extension("hello", ["hello.pyx"])] setup( name = 'C extention module example', cmdclass = {'build_hello': build_ext}, ext_modules = hello_modules )
利点、欠点
利点
- Pyrexの上位互換
- Pyrexよりも高機能
欠点
- setup.pyが追加で必要
Pyrexでは必要の無いsetup.pyを追加で必要とは言え、Pyrexよりも高機能な点が大きいと感じます。
Pyrexを使うのであれば、上位互換であるCythonを採用するべきでしょう。
またPyrexも含めてですが、中規模開発までならなんとかなるかと思います。
SWIG
SWIGはC/C++で書かれたライブラリを様々な言語のライブラリとして利用することが出来ます。
例えば、Perl、PHP、Python、RubyといったLLからJAVA、C#等にも対応しています。
さらにはTcl/Tk、Lua、Go、Modula-3等といった使用頻度が低い言語までサポートしています。
ctypes、Pyrex、CythonはC言語でライブラリを書く苦労をいかに減らすか、という点を目標にしていると言えます。
しかしSWIGはこれらとは異なり、C/C++でライブラリ開発をいかに開発しやすくするか、という点を目標に置いています。
ソースコード
/* hello.c */ #include <stdio.h> void hello(void) { printf("Hello World!!\n"); }
SWIGはライブラリのソースコードと「.i」、「setup.py」が必要です。
hello.i
%module hello %{ extern void hello(void); %} extern void hello(void);
#setup.py from distutils.core import setup, Extension hello_module = Extension('_hello', sources=['hello_wrap.c', 'hello.c'], library_dirs=["/opt/local/lib/"], ) setup (name = 'hello', version = '0.1', author = "nil", description = """hello""", ext_modules = [hello_module], py_modules = ["hello"], include_dirs=["/opt/local/include/"], )
その他
上記に挙げた以外でも高速化を行う為の方法が用意されています。
調べただけでも、Psyco、Psychotic、boost.python等が見つかりました。
まとめ
いかがだったでしょうか。
ソースコードは入門用のHello Worldでしたが、それぞれの基本的な使い方を説明してきました。
このまま十分応用できるかと思います。
C/C++でライブラリを作成するには敷居が高いですが、その見返りは非常に大きいです。
今回紹介したライブラリにはその敷居を低くするCython等もあります。
また、今回紹介できなかったPsycoも魅力的です。
Pythonはライブラリの多さも魅力の1つで、その中に今回紹介した物も含まれています。
LLでもC/C++に負けない高速化が比較的可能に行えることがお分かり頂けたかと思います。
日本ではPythonを利用する人は少ないですが、この機会にPythonを始めてはいかがでしょうか?
最後になりましたが、コメントやハテぶなどでのご意見もお待ちしています。
より詳しい使い方が知りたい等の意見が多ければ続きも書いていきたいと思います。