2011-05-01

pypyで何も考えずにpythonを高速化する

Python公式のCPythonよりも高速という噂のpypyPython2.7.1相当の機能を実装したというので、その実行速度を測定しました。



■インストール(OSX)

pypyのインストールは非常に簡単で、本家からbzipをダウンロードして解凍したらできあがりです。


$ tar xjvf pypy-1.5-osx64.tar.bz2
$ cd pypy-c-jit-43780-b590cf6de419-osx64
$ ls
LICENSE README bin include lib-python lib_pypy site-packages

binの中にpypyというコマンドがありますので、それを実行すると起動します。


$ bin/pypy

Python 2.7.1 (b590cf6de419, Apr 30 2011, 03:30:00)
[PyPy 1.5.0-alpha0 with GCC 4.0.1] on darwin
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``how to construct the blackhole
interpreter: we reuse the tracing one, add lots of ifs and pray''
>>>>

>が3つではなく4つ出てくるところが、公式CPythonよりも強そうですよね!



■実測

実際にPython標準のパフォーマンス測定ツールtimeitで、実行速度を比較してみました。

比較のため、OSX上のCPython2.6.1, 2.7,1とpypyを使いました。



まずは単純に配列を作る処理。


------- CPython 2.6.1
>>> import timeit
>>> t = timeit.Timer(stmt="[x*x for x in xrange(1000)]")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
184.11 usec/pass

------- CPython 2.7.1
>>> import timeit
>>> t = timeit.Timer(stmt="[x*x for x in xrange(1000)]")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
153.30 usec/pass

------- pypy 1.5
>>>> import timeit
>>>> t = timeit.Timer(stmt="[x*x for x in xrange(1000)]")
>>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
120.95 usec/pass


CPython2.7は2.6よりもだいぶ速いですが、それをさらにpypyが上回る速度です。




次に、集合(set)の中の検索


------- CPython 2.6.1
>>> t = timeit.Timer(setup="a=set([x*x for x in xrange(100)])", stmt="[(x in a) for x in xrange(100)]")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
23.41 usec/pass

------- CPython 2.7.1
>>> t = timeit.Timer(setup="a=set([x*x for x in xrange(100)])", stmt="[(x in a) for x in xrange(100)]")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
19.59 usec/pass

------- pypy1.5
>>>> t = timeit.Timer(setup="a=set([x*x for x in xrange(100)])", stmt="[(x in a) for x in xrange(100)]")
>>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
11.97 usec/pass

これも結果は同様に圧倒的にpypyが高速。(2.7の2倍に迫る速度!)



こんなに簡単に高速化できるなら、どこかで試しに使ってみたくなりますよね。