promiseはPythonの関数の実行速度を高速化するためのモジュール。
デコレータ関数を使って,関数のバイトコードを書き換えることによって関数の実行速度を高速化する。
実際どのくらい高速化されるのか試してみよう。Pythnonの標準モジュールdecimalの__new__()メソッドにpromiseを使い,使わなかったケースと実行速度を比較してみた。
def foo():
D = decimal_p.Decimal
D('3.14')
D((0, (3, 1, 4), -2))
D(314)
D(' 3.14 \\n')
promiseを使わないケース |
@promise.constant(__builtins__)した場合 |
---|---|
約5.47秒 |
約5.03秒 |
promiseは,オブジェクトの参照時,Name Lookupを出来るだけしないようにパイとコードを書き換えることで関数の実行を高速化している。先ほどの例で使ったpromise.constant(__builtins__)では,デコレータとして利用することでPythonの組み込み(Builtin)名前空間にあるオブジェクトを直接参照するようにバイトコードを書き換える。Pythonには3つの名前空間があるが,通常関数内でオブジェクトを参照するとき,まず関数の名前空間から名前を探し,その後モジュール,組み込みと名前空間をさかのぼってゆく。つまり3回名前の探索(Name Lookup)を行うわけだ。promiseは,isinstance()のような組み込みオブジェクト(関数)をリファレンスとしてバイトコードに埋め込むことで,Name Lookupにかかる時間を削減する。
また,promise.pure()をデコレータとして関数に添えると,関数のバイトコードを関数呼び出しをしている部分に埋め込む。こうすることで,関数呼び出し(Pythonでは関数もオブジェクトなのでオブジェクト参照)に伴うName Lookupを無くし,関数呼び出しのオーバーヘッドを無くして高速化を図る。
自動的に行われる最適化と違い,promiseはデコレータとして関数に対して適用する必要があるので,使うのに頭を使う。また,副作用がまったくないわけではない。
しかし,実際に高速化の効果があるし,仕組みもシンプルで,メカニズムを分かって使えばリスクも低いはずだ。なかなか面白い高速化のアプローチかも知れない。