Python
oracle
ベンチマーク
graalvm
graalpython

Python標準実装より速い!?Oracleが作ったGraalPythonをJython・CPythonとベンチマークしてみた!!

GraalVM・GraalPythonとは

image.png

GraalVMは2018年4月27日にOracleから公開された仮想マシンです.

GraalVM is a universal virtual machine for running applications written in JavaScript, Python, Ruby, R, JVM-based languages like Java, Scala, Clojure, Kotlin, and LLVM-based languages such as C and C++.

GraalVMはJavaScript,Python,Ruby,R,JavaやScala,Clojure,KotlinのようなJVMベースの言語,CやC++のようなLLVMベースの言語で書かれたアプリケーションを動かすための仮想マシンです.

ちょっと何を言ってるかわからないと思いますが,私も分かりませんでした.
GraalVMは本当にこの通りで,jsやPythonのようなスクリプト言語も動き,ScalaやKotlinのようなJVM言語も動き,LLVMベースのバイナリも動く仮想マシンです.

公式サイトを見てもらうと一番早いのですが, 

image.png

本当に信じられないぐらいの数の言語が動く環境が公開されています.
これらの中に,GraalPythonというGraalVM上で動くPython実装が公開されています.

GraalPythonはCPythonよりどれくらい早いのか?

ということをベンチマークしていきたいと思います.

GraalPythonの導入

非常に簡単です.
公式サイトのダウンロードに行き,tar.gzをダウンロードしていきます.
あとは

# 解凍
$ tar xvf graalvm-ce-1.0.0-rc8-linux-amd64.tar.gz

# Pythonバインディングのダウンロード
$ ./graalvm-ce-1.0.0-rc8/bin/gu intall python

# GraalPythonの実行
$ ./graalvm-ce-1.0.0-rc8/bin/graalpython 
Please note: This Python implementation is in the very early stages, and can run little more than basic benchmarks at this point.
>>> 

これだけで導入できます!!

Jythonって何?

以前に書いた記事で,Jythonについては取り上げたことがあります.

Pythonマイナー環境列伝 ~あなたはいくつのPython環境を知っているか?~

image.png

いわゆるJVM上で動くPythonの実装です.普通のPythonと違い,Javaのライブラリが使えたりします.
過去に作られたJVM上で動く,Java実装のPythonはどこまで健闘できるのか?
ということも検証してみます.

導入方法もUbuntuなら簡単でこんな感じで導入できます.

$ apt-get install jython
$ jython --version
Jython 2.7.1

しかし,現在,Jythonは開発が停止しているらしく,Pythonの2.7系までしか対応していません.

ベンチマーク

今回,比較対象とするCPythonは

$ python3 --version
Python 3.6.3

実行する内容は前の記事を参考にやっていこうと思います.

GoとPythonとGrumpyの速度ベンチマーク ~Googleのトランスパイラはどれくらい速い?~

モンテカルロ法による円周率の求解によるベンチマーク

実験方法

プログラミングの教本でもよくある円周率のモンテカルロ法による計算をベンチにしました.
よい解説があったので引用で貼っておきます.
試行回数により,処理時間がどのように変化するかを観察します.

image.png

引用:モンテカルロ法と円周率の近似計算

実装

monte_py.py
#coding:utf-8
import random
import sys

if __name__=="__main__":
    num = int(sys.argv[1])
    c = 0
    for i in range(num):
        x = random.random()
        y = random.random()
        if x * x + y * y <= 1.0:
            c += 1

    print(4.0*c/num)

結果

繰り返し回数 Python[sec] Jython[sec] GraalPython[sec]
1000000 0.941 7.139 4.105
2000000 1.858 9.553 4.816
3000000 2.988 13.913 4.969
4000000 4.022 14.959 5.141
5000000 5.435 21.144 6.349
6000000 7.026 25.413 6.774
7000000 8.701 34.169 7.361
8000000 13.682 61.787 13.847
9000000 15.613 40.517 7.044
10000000 10.684 33.798 5.451
11000000 11.394 26.569 5.402
12000000 12.661 38.839 6.846
13000000 17.158 63.671 7.655
14000000 16.572 47.804 6.156
15000000 19.187 57.862 7.904
16000000 25.037 87.531 7.333
17000000 19.235 54.170 6.315
18000000 18.775 68.362 8.148
19000000 29.085 68.262 6.802
20000000 21.175 65.696 6.590

image.png

GraalPython > CPython >> Jython

考察

繰り返し回数が小さいときにはCPythonが速いですが,繰り返し回数が大きくなってくるとGraalPythonのほうが速い.という傾向がみられました.一方でJythonはすごく遅い.
こう見るとGraalPythonは中でJITによる高速化が効いているようですね.それによりこのように高速化されているのではないでしょうか.JVMにもJITが入っているので速くなっても不思議ではないのですが,Jythonのほうは速くなりませんね・・・

竹内関数によるベンチマーク

竹内関数とは

竹内関数(たけうちかんすう)は、プログラミング言語処理系のベンチマークなどに使われる、再帰的に定義された関数である。

image.png

参考:竹内関数

実験方法

Tarai(n,n-1,0)という形で竹内関数を呼び出し,nの大きさと処理時間にどのような変化があるのかを観察する.

実装

tarai_py.py
#coding:utf-8
import sys

def tak(x,y,z):
    if x<=y:
        return y
    else:
        return tak(tak((x - 1),y,z), tak((y - 1),z,x), tak((z - 1),x,y))

if __name__=="__main__":
    a,b,c = map(int,sys.argv[1].split())
    print(tak(a,b,c))

結果

n CPython[sec] Jython[sec] GraalPython[sec]
10 0.370 19.500 1.679
11 2.167 23.383 2.448
12 11.929 16.079 2.062
13 58.507 24.814 5.823
14 453.833 115.069 43.099

image.png

nが小さいとき
CPython > GraalPython > Jython

nが大きいとき
GraalPython >> Jython > CPython

考察

面白いグラフになりました.nが小さいときはCPythonが速いですが,nが大きくなるにつれ,JythonやGraalPythonが速くなる.という結果になりました.これはJITが効いているように思います.
以前にも似たような検証をしたことがあって,C言語で作った竹内関数のベンチマークとJavaで作った竹内関数のベンチマークをしたことがあります.その時も,nが大きくなった時,Javaのほうが速くなる.といったことが起こりました.このような再起が多く行われる関数だと,Javaのほうが速くなる.ということはままとしてあるようです.そのため,JVMベースのJythonや,それを踏襲したGraalVMを使ったGraalPythonがCPythonを凌駕する速度になることは,割とありえることなのかもしれません.

まとめ

もともとJVM周りのスクリプトの対応について調べていたところ,GraalPythonを見つけました.そこでGraalVMを知り,あれ?これってJVMと何が違うんだっけ?という疑問から,過去にあったJythonとベンチマークの比較をしてみました.
GraalPythonを少し触ってみましたが,やはり少し機能が足りないな.という気持ちもあります.例えば,python3にはビルトインの関数で,inputがありますが,GraalPythonにはありません.(おそらくinput関数の実装をGraalVM上で実装するのは大変そうですが・・・)
それにしても,時間がかかるような処理.Pythonで5秒以上かかるようなCPUバウンドな処理をすると,GraalPythonのほうが速くなる.というのは驚きでした.
まだいろいろなライブラリ周りと合わせて使っていないので,どんなバグが起こるかわかりませんが,一度いろんなライブラリを試してみるのはいかがでしょうか?