Grumpy(Go running Python)を試してみた。

#序

「すごくスケールする」、とかうまく書くものだなぁ、と
以下のニュースにある意味感心したので、Grumpy(Go running Python)を試してみることに。
[マイナビニュース : Google、すごくスケールするPython実行環境をGoで開発](http://news.mynavi.jp/news/2017/01/06/110/)

#ネタ元のブログを読む。

上記事の中身、《すごくスケール》という見出しを作るために元ブログを抜き書きした気がしたりするので、ネタ元のブログ(元ブログ)の方も斜め読みしておこう。。

https://opensource.googleblog.com/2017/01/grumpy-go-running-python.html

## Fibベンチマークにおける高スケーラビリティについて
> 《すごくスケール》での記述 : 「Grumpy」はまだ実験段階とされているものの、CPythonと比較してFibベンチマークで高いスケーラビリティを発揮している。

=> 元ブログでの記述。

> In particular, Grumpy has no global interpreter lock, and it leverages Go’s garbage collection for object lifetime management instead of counting references. We think Grumpy has the potential to scale more gracefully than CPython for many real world workloads. Results from Grumpy’s synthetic Fibonacci benchmark demonstrate some of this potential:
 

Global Interpreter Lock（グローバルインタプリタロック, GIL）については、[日本語wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%97%E3%83%AA%E3%82%BF%E3%83%AD%E3%83%83%E3%82%AF)も分かりやすい。PythonとスレッドセーフでないCのコードの組み合わせは、プロセス毎にロックがかかることがスケーラビリティを制限するということ。元ブログ中に載っているベンチマーク結果は以下の通り。

![](https://lh6.googleusercontent.com/AJtJgMwyxN3KWnDrHW5JhersJGuf1SsR_lhhQoUY5gSMBjhV-BJo-vWh4JztqD7qq9pcr0JYT-niwehvDqvCmM8ZhCUAkgZFpviWnNKah5xGJCNGuMAGBdhYYhT3ZbN-HDfw_Fs3)

シングルスレッドではGrumpyの方が遅いけど、マルチスレッドではリニアに処理能力がスケールしていることがわかる。ただし、この結果はPythonとCの拡張モジュールのサポートを打ち切ったがゆえにである。

> （元ブログ）First, we decided to forgo support for C extension modules. This means that Grumpy cannot leverage the wealth of existing Python C extensions but it gave us a lot of flexibility to design an API and object representation that scales for parallel workloads.

##Grumpyのエコシステムについて

以下の記述は、けっこうミスリーディングと思ったので、実際のところを確認しておこう。

>《すごくスケール》での記述 : Goはもともと並列処理で高い性能を発揮することを目指して開発されており、並列処理を得意としている。互換性の面でGrumpyにはまだ開発時間が必要と見られるが、マルチコア/プロセッサで高い性能を発揮するGrumpyは今後重要性の高いPython実行環境として利用が進む可能性がある。

元ブログだと=>

>
Second, Grumpy is not an interpreter. Grumpy programs are compiled and linked just like any other Go program. ... the biggest advantage is that interoperability with Go code becomes very powerful and straightforward: Grumpy programs can import Go packages just like Python modules!
(言っているところ):Pythonから生成されたGrumpyプログラムは、他のGoプログラムと同様にコンパイルされリンクされる...このことの最大のアドバンテージは、Goとの相互運用性だ。Grumpyプログラムは、ただのPythonモジュールのようにGoパッケージをインポートできる。

Grumpyは、Cコードの呼び出しを諦めた時点で、既存のpythonコードをGo上で動かすことをおそらくは意図していない。今後のGrumpy周りの開発は、Djangoなど既存のPythonフレームワークを動作させるといった方向ではなく、GoのライブラリとPythonのコードとを組み合わやすくする方向に進んで行くのではないかと。

#Grumpyを実行してみる。

Grumpyがどんなコードを吐き出すか知りたかったので、Grumpyを動かしてみた。
元のコードはこんな感じ。

```benchmark1.py
#-*- using:utf-8 -*-
import time
if __name__ == '__main__':
    start = time.time()
    for i in range(1,50):
        print (i, 100.0 / (i * i * i ))
    elapsed_time = time.time() - start
    print ("------- result ------")
    print (elapsed_time * 1000 , "ms")

```
Cpythonでの実行時間は1.3msくらい。

> $ python benchmark1.py 
(1, 100.0)
(2, 12.5)
..(略)..
(49, 0.0008499859752314087)
------- result ------
(1.3232231140136719, 'ms')

Grumpyを導入する。Go、python、そして、gccが入っているLinux(ubuntu16.04)の場合、githubサイトの指示とおり導入は簡単だった。

>git clone https://github.com/google/grumpy
cd grumpy
make
export GOPATH=$PWD/build
export PYTHONPATH=$PWD/build/lib/python2.7/site-packages
tools/grumpc benchmark1.py > benchmark1.go
go build benchmark1.go

benchmark1.goから作られたbenchmark1バイナリを実行してみる。

> $ ./benchmark1 
(1, 100)
(2, 12.5)
..(略)..
(49, 0.0008499859752314087)
------- result ------
(5.621671676635742, 'ms')

...予想通り、Cpythonより時間がかかっているね。

Grumpyが生成したGoのソースコードは長いので、以下に置いておく。
現時点では、人間が読むべきものではなさそう。。

https://gist.github.com/kmry/906a8154a37bb0060d35eee20a3e06ca

#気になった人は...

grumpyによるpythonコード on Go が気になった人は、まずはgithub上のコードを眺めていくのが良いと思う。python標準ライブラリ互換のGo実装もある程度進んでいる。

例えば、上で実行時間を測るのに使ったtimeモジュールを調べてみると、
https://github.com/google/grumpy/search?q=time

以下のように、Goの標準ライブラリでラップされた実装になっていることがわかる。

```grumpy/lib/time.py
"""Time access and conversions."""

from __go__.time import Now, Second, Sleep  # pylint: disable=g-multiple-import


def sleep(secs):
  Sleep(secs * Second)


def time():
  return float(Now().UnixNano()) / Second
```

こうした努力の延長線上に、「すごい人」が現れた場合、PythonのWAF互換なフレームワークがgrumpys上に現れるのかもしれない。 #未保証 :) 

もうちょっと情報が出そろった後ならば、pythonでgoライブラリを用いた並列処理記述をするのも楽しいかもしれない。