最近、仕事でPyPy3を試したりしているので、メモを書き残しておく。
PyPy - Welcome to PyPy
インストール
今回はUbuntu 14.04LTSで試した。PyPy3はPPAリポジトリに無いので、Linux向けのコンパイル済みバイナリをダウンロードして使うことにした。
利用するときは、virtualenvでpypy3用の環境を作っている。
$ wget https://bitbucket.org/pypy/pypy/downloads/pypy3-2.4.0-linux64.tar.bz2 $ bzip2 -dc pypy3-2.4.0-linux64.tar.bz2|tar xf - $ sudo mv pypy3-2.4.0-linux64 /opt/ $ sudo ln -s /opt/pypy3-2.4.0-linux64/bin/pypy3 /usr/bin/pypy3
virtualenvで利用する際には --python=pypy3 と指定する。
$ virtualenv --python=pypy3 venv-pypy
互換性について
PyPy3 2.4.0は、CPython 3.2.5互換とのことなので、CPython 3.3以降で導入されたシンタックスが使えないところは気をつけないといけない。
例えば、文字列リテラルに「u」をつけれない点。だたし、これは最初からPython3向けで書いていたコードならそもそも「u」は不要だし、気にしなくてもよさそう。
C言語で書かれたサードパーティ製のモジュールは動かないものが多いので、その場合はPure Pythonのもので代用する必要がある。
今回PyPyを適用したコードは、Python3.4向けに書いていたものであったが、アプリケーションロジックは一行も変更せずに動かすことができた。
互換性は高いと思う。
PyPyを適用するにあたって一点だけハマったところがあった。
「virtualenvでpypy3を動かした際に、出力のリダイレクトを指定するとエンコーディングがasciiになってしまう」というもの。
(venv-pypy)tokibito@ubuntu:~$ python -V Python 3.2.5 (b2091e973da6, Oct 19 2014, 18:29:55) [PyPy 2.4.0 with GCC 4.6.3] (venv-pypy)tokibito@ubuntu:~$ cat test.py import sys sys.stdout.write(sys.stdout.encoding + '\n') sys.stdout.write("日本語\n") (venv-pypy)tokibito@ubuntu:~$ python test.py > hoge Traceback (most recent call last): File "test.py", line 4, in <module> sys.stdout.write("日本語\n") File "/home/tokibito/venv-pypy/lib-python/3/encodings/ascii.py", line 22, in encode return codecs.ascii_encode(input, self.errors)[0] UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) (venv-pypy)tokibito@ubuntu:~$ cat hoge ascii
環境変数のPYTHONIOENCODINGにUTF-8を指定することで回避はできたけど、原因は特定できていない。
virtualenvを使わないでpypy3やpython3.4コマンドで実行すると、特に問題は発生しなかった。
パフォーマンスについて
今回PyPyを適用したコードは、ボトルネックが「2重ループ内での巨大なリストに対する値の参照と比較」となっていたバッチ処理。
データベースの参照やファイル読み込みについては、ループに入る前にすべて読み込んでキャッシュ済みの状態。
データベース接続と問い合わせはDjangoフレームワークのものを使っている。(Django1.8+pymysql)
PyPyを試す前に、cProfileを使って明らかに遅い処理は修正済みの状態。
Python3.4で実行した場合におよそ30分かかっていたもの。
(venv)$ time python manage.py my_script # Python 3.4の場合 real 30m34.483s user 30m34.061s sys 0m0.373s
これをPyPy3で動かした結果、6分程度で終了した。
(venv-pypy)$ time python manage.py my_script # PyPy3 2.4.0の場合 real 6m37.536s user 6m37.238s sys 0m0.289s
この他、同様に600分程度かかっていたバッチ処理が150分程度に短縮されるなど、CPythonの速度がネックになっていた処理はかなり速くなった。