比較:並行処理 - Java とScala とGo -


こんにちは、馬場です。

完全に出遅れていますが、個人的に触ってみたかったGo言語と戯れてみたいと思います。Go 言語といえば並行処理ですよね。せっかくですので、他の言語Java 8 / Scala 2.11 と比較しながら見ていきたいと思います。

お題:二分探索木を比較する。

並行処理のお題は、超充実しているGo 言語のチュートリアルTour of Goのエクササイズ、Equivalent Binary Tree です。

二分探索木とは、子の数が最大2である二分木で、「あるノードの左の子およびその全ての子孫ノードの持つ値はそのノードの値より小さく、右の子及びその全ての子孫ノードの持つ値はそのノードの値より大きくなるように構成した」もの(Wikipedia)です。

2つの二分木が、形はちがえど同じ値を保持している場合があります。そのために、

1. 二分探索木を生成し、
2. 2つの二分木の解析(=どのような値を保持しているのか)を並行して行い、
3. その後解析結果を比較する

処理を3つの言語で実装します。

1. Java 8

まずは、二分探索木を生成するクラスです。

このTree の解析をするメソッドを実装します。

お気づきの通り、ここまで並行処理全く関係ありません。それでは、2つのTreeを解析し、保持する値が同じかどうか確かめてみましょう。2つのTreeの解析は並行に行います。

Java8 で追加された CompletableFutureを利用して、2つのTreeの解析を並行で実行しています。CompletableFuture.supplyAsync は 引数に指定した処理を非同期で実行します。Futureのgetメソッドは、処理が終わった段階で値を返してくれます。ラムダ式もうまく使われていて、コードも非常に簡単。Thread だ、synchronized だと言っていた一昔前のJavaエンジニア(私です)からみると隔世の感があります。

2. Scala 2.11

次はScalaです。二分探索木を生成するクラスは以下のようになりました。ScalaらしくOptionを使います。

このTree の解析をするメソッドを実装します。

それでは、2つのTreeを解析し、保持する値が同じかどうか確かめてみましょう。2つのTreeの解析は並行に行います。

Scala のFuture は「処理が終わったらその値を取得する」ということができません。完了時のcallback関数を設定する方式(onSuccessで指定しているブロック)です。とはいえ、上記のようなfor文を書くことにより、複数の処理を最後に同期させて結果を比較することができます。

3. Go

さて、これをGo で実装するとどうなるのでしょう?二分探索木を生成するクラス。これは、Go のチュートリアルを参照してください(というか、ここまでのプログラムはこのGo のプログラムをJava や Scala で書き直したものです)。
Tree を解析するメソッド、同じかどうか判定するメソッドは以下のようになります。

Future を利用していたJava やScala とだいぶ趣が違いますね。Go には チャネル(Channel)と呼ばれるものがあり、このチャネルを通して値の送受信が可能です。そこで、このチャネルをつかってTreeの解析と並行して行い、結果を比較しています。
Walk 関数内では、Treeに含まれる値を小さい順にどんどんチャネルに送ります。goroutineを利用してWalk関数は並行して実行します。Same関数では、チャネルの値を順番に取り出して比較することによって、2つのTreeが同じ値を持っているか、評価します。

Go の何がうれしいのか?

並行処理と言えばGoという評判ですが、それはやはりこの goroutineとチャネルの仕組みがあるからこそなのでしょう。特にチャネル。Java や Scala が利用しているFutureはTreeの解析を全部し終わってから同じかどうか評価しています。Goのチャネルは、値を受け取ったらその都度値を取り出して処理を行っています。二分木が大きく探索に時間がかかる場合、少しでも違いがあれば処理が終了し早く終わります。サービス的プログラムを書くのにもよさそうですね。

やってみてわかったこと

Goと本当に軽く戯れてみてわかったことは、チュートリアルの充実です。個人的にプログラミング言語を学ぶときの最初の障害はプログラミング環境をつくるところだと思っているのですが、その点このチュートリアルにはブラウザ上からプログラムを試す環境がついていて、非常に楽でした。他の言語もこれくらいわかりやすく「とにかくまずはやってみよう」と思った人フレンドリーなチュートリアルがあればいいな、と感じました。(Java のチュートリアルは、JVMの説明から入る来るものを拒む仕様...)

また、久しぶりにJava を調べてみて、Java 8 になって書きやすくなったと感じました。重い処理を複数のスレッドにわけて実行し、あとで結果をマージするような使い方であれば、Java8 の書き方が一番わかりやすいでしょう。

それでも一番好きなのはScalaです。

みなさんの開発の場でどれほど言語選択の自由があるのかわかりませんが、何かの参考になればうれしいです。


Comments

  • xuwei_k  On 2015年2月28日 at 16:03

    > Java や Scala が利用しているFutureはTreeの解析を全部し終わってから同じかどうか評価しています。Goのチャネルは、値を受け取ったらその都度値を取り出して処理を行っています。二分木が大きく探索に時間がかかる場合、少しでも違いがあれば処理が終了し早く終わります

    という箇所、まずScalaやJavaのプログラムをそのように書いてないコト自体が問題で(それを書いた場合どのくらい面倒か、という別の問題があるが、書けないことはないはず)、それを試さずにGoを褒めるのはおかしいと思うので、そういう意味では比較として微妙だと思うのですが

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です