はじめに
PyPyとは?
Pythonの実装のひとつ。
Pythonモジュールをふつうに実行できます。素のPythonで走らせるよりも圧倒的に高速で動作します。(この記事の最後で簡単な速度比較をします)
一方で、利用できるライブラリには限界があるようです。正確に把握していないのですが、サードパーティライブラリはほぼ使えないと思ったほうがよいというイメージ(後述しますがnumpyは使えるようです)。標準ライブラリは使えます。
したがって、標準ライブラリで済むシンプルなPythonスクリプトを速く実行したい、というときに便利です。
なぜDocker?
ローカルマシンの環境を汚したくないので仮想環境を作りたいのですが、PyPyでの仮想環境の作り方についてあまり情報が見つかりませんでした。
最近Dockerの勉強をしていることや、WindowsのPython環境の動作が怪しいと思うこともあって、じゃあDockerで環境作ろうと思いました。
環境
- Windows 10 Home (バージョン20H2 ビルド19042.685)
- WSL2でDockerが使える環境
最近はWindows10 HomeでもWSL2でDockerが動くようになって非常に使いやすくなりました。WSL2のインストール方法はたとえばMicrosoftの公式ページを参照してください。その後、Docker Desktopの設定でWSL2を使うよう指定すればOKです。
Macでもほぼまったく同じ手順でできるはずです。
手順
では、PyPyの実行環境をDockerで構築する手順を説明していきます。
ディレクトリ構成
以下のようにディレクトリを構成します。
│ docker-compose.yml
└─src
main.py
ファイル作成
docker-compose.yml
ファイルを以下のように作成します。
version: '3'
services:
pypy:
image: pypy:3
volumes:
- ./src/:/src
working_dir: /src
tty: true
サービス名をpypy
としていますが、何でもよいです。あとでこの名前でコンテナに入るので、自分にとって分かりやすいようにプロジェクト名をつければ良いと思います。
image
でDockerHubからPyPyのイメージを持ってきています。
volumes
でホストPCのsrcディレクトリをコンテナのsrcディレクトリにマウントしています。これでホストPCの編集がコンテナに反映されます。
working_dir
でsrcディレクトリを指定することで、あとでコンテナに入るときにここに入ることができます。
tty
をtrueにすることで、コンテナを立ち上げたあと起動しっぱなしとなり、コンテナに入ることができます。
main.py
は以下のようにHello worldするだけです。
print("Hello, world!)
実行
docker-compose.yml
のあるディレクトリでコマンドプロンプトを開き、以下のコマンドでコンテナを立ち上げます。
>docker-compose up -d
初回はちょっと時間がかかります。
オプション-d
をつけることでバックグラウンド実行となり、このあとのコマンド操作が可能になります。
コンテナが立ち上がったら、以下のコマンドでコンテナに入ります。
>docker-compose exec pypy bash
ここで、引数pypy
はdocker-compose.ymlファイルでサービス名としてつけたものです。
引数bash
はコンテナに入ったあとbashで操作を行うために必要です。というかこの引数がないとエラーになります。
コンテナ内のsrcディレクトリに入ったので、直下にmain.py
があります。
pypyコマンドで実行できます。
# pypy main.py
Hello, world!
ソースの編集
srcディレクトリをマウントしているので、ホストPCでの編集結果がコンテナにも反映されます。
たとえば下記のようにホストPCでmain.pyを編集し、コンテナで再度実行すると、たしかに反映されていることが分かります。
print("Hello, world!hogehoge)
# pypy main.py
Hello, world!hogehoge
ライブラリの管理
ライブラリはpipでインストールできます。たとえばコンテナ内で下記コマンドでnumpyをインストールできます。
# pip install numpy
※Pythonで使えるライブラリを全てPyPyで使えるわけではないらしいですが、どうやらnumpyは普通に使えるみたいです
以下のようにnumpyを実行するスクリプトを書いて試してみると、たしかに実行できています。
import numpy as np
print(np.array([1, 2, 3]))
# pypy np_test.py
[1 2 3]
コンテナ終了
使い終わったらexitコマンドでコンテナから抜けます。
# exit
コンテナは立ち上げっぱなしでもいいですが、使い終わったら落としておくとよいと思います。
>docker-compose down
使うときはもう一度docker-compose up -d
します。2回目以降はホストPCにイメージが残っているので、素早く立ち上がります。
補足
###なぜdocker-compose?
docker-compose up
コマンドで一発でコンテナを立ち上げたかったから。
もちろんDockerfileを作ってビルドしてからdocker runしてもいいのですが、そうするとコマンドに色々引数をつけなきゃいけなくなって面倒だと思ったので。
DockerHubのPyPyイメージのページではそのようなやり方が説明されています。
PyPyの速度検証
ついでなので、PythonとPyPyの速度を比べてみます。
以下の記事を参考に、39番目のフィボナッチ数を求めるスクリプトを書いて速度を比較してみました。
【まとめ】フィボナッチ数だけで50ぐらいのプログラム言語に精通したつもりになる
import time
def fib(n):
if n < 2 :
return n
else:
return fib(n-2) + fib(n-1)
# 39番目のフィボナッチ数を求めるまでの時間を計測する
s = time.time()
print(fib(39))
e = time.time()
print("time: " + str(e - s) + "sec")
結果は以下のようになりました。
- PyPy: 0.958sec (バージョン7.3.3)
- Python: 28.868sec (バージョン3.7.3)
圧倒的にPyPyが速いですね。元記事ではもっと色々な言語の速度が比較されていますので、ご参考までに。
おわりに
PyPyは速度が速くて便利だと思うのですが、いまいち情報が少ないです。だれかのお役に立てれば幸いです。
私は秘境集落探索ツールというものを作成しまして、これのデータ前処理にPyPyを使ったのですが、素のPythonでは永遠に終わらないような処理がすぐに終わって感動しました。よければこのツールも遊んでやってください(宣伝)。
(追記)続編(?)として「PyPyとPythonの実行環境をDockerで構築するを公開しました。今回はPyPyの実行環境のみを扱いましたが、この記事ではPyPyと素のPythonを併用できる環境について解説しています。