10/23 9:50 訂正&追記: GradleがデフォルトでDaemon起動すると書いてた件 (thanks to きょんくん)
元記事: http://dev.classmethod.jp/server-side/gradle/gradle-first-contact/
経緯的な
id:daisuke-mが昼過ぎに技術を語るいつものシリーズにGradleを追加した旨のツイートをしてました。 生粋のGradlerとしては喜び勇んでチェックしてみたんですが、「Gradleのインストール」であるべきところを「Groovyのインストール」と書いてたので、親切心でコメントしたわけです。
@daisuke_m "Groovyのインストール"->"Gradleの〜"
— Yasuharu Nakano (@nobeans) 2013, 10月 22
そこまでは良かったのですが、ちょっと調子に乗ってしまいまして、
@daisuke_m つ "ついでにせっかくなのでGroovyもインストールしておきましょう。`gvm install groovy`"
— Yasuharu Nakano (@nobeans) 2013, 10月 22
@daisuke_m 要るかどうかなんて関係ないのです。そこにgvmがあるから入れるのです。groovyを入れたらgroovyservも一緒に入れるのです。
— Yasuharu Nakano (@nobeans) 2013, 10月 22
と書いたところ、記事に晒し上げされてしまいました。 なんということでしょう。
そのままフェードアウトしてくれれば終わればまだ良かったのですが、自称怖くないモンスターの人に見付かって問い詰められているid:daisuke-mが忍びなさMAXでつい反応してしまったら、気がついたら私がGroovyServとGradle Daemonの違いについてなんか書かなければならない流れになっておりました。
ああ、恐ろしきかな因果の流れ。
GroovyServとは
Groovyコマンドを実行可能なJVMプロセスをサーバとして常駐させておいて、ネイティブコマンドを使ってTCP経由でコマンド引数をサーバに送り込み、評価した結果を再びTCP経由でもらって出力する、という拙作のツールです。
Groovyに限らずJVM系言語でスクリプトを書いた場合、JVMプロセスを起動して色々なクラスローディングする準備処理が遅くて、1秒ぐらいの待ち時間が発生します。
$ time groovy -e "println 'Hello'" Hello real 0m1.347s user 0m1.481s sys 0m0.168s
GroovyServをインストールして、クライアントコマンド経由で実行すると
$ time groovyclient -e "println 'Hello'" Hello real 0m0.057s user 0m0.002s sys 0m0.005s
すごく...はやいです...。
といっても、初回はサーバプロセスを起動するための待ち時間が数秒かかるんですけども。 一度起動したらそれ以降は上のような感じです。 はいはい、爆速爆速。
なお、mainクラスのエントリポイントを指定できればいいので、JythonとかClojureも同じように高速化できます。 Scalaのコンパイルも頑張れば早くなるようです。 Vim+QuickRunでgroovyConsole風にさくっと実行できるのにフル機能エディタ!みたいなこともできますし、SublimeText2からも似たようなことができます。
一応このネタで2013/5にGr8conf EU 2013というデンマーク コペンハーゲンのGroovy系カンファレンスで発表してきたりしました。
詳しくは、ちょっと雑多な感じですがユーザガイド(日本語)をどうぞ。
Gradle Daemonとは
Gradleも同様にJVM上で動作するツールなので、起動の待ち時間が大変遅いわけです。 毎回JVMプロセスを一から起動してると、さくさくビルドやテストを試せません。 GroovyServみたいな仕組みが欲しいですよね。
ということで、Gradle本体が同じような仕組みを用意したのがGradle Daemonです。 歴史的に言うと、GroovyServの方が若干早いはず。 パクられた!とは言いませんが、時期的なものを考えると多少は参考にされたんじゃないかと自意識過剰気味にアピールしておきます。どうかな。違うかも。
最近のGradleはデフォルトでDaemonを利用します。
GradleがデフォルトでDaemon起動すると書いたな、アレは噓だ。
--daemon
オプションが必要です。
以下はしれっと書き換えてあります。
すいません。
--daemon
オプションはまだデーモンがいなければ起動して使い、すでに居ればそれを使うというオプションです。
というわけで、適当なGradleプロジェクトで、2回gradle --daemon tasks
を実行してみると、2回目が劇的に早くなってるんじゃないかと思います。
たとえば、自宅のかなり古いMacBook mid 2008で試してみると、
$ gradle --daemon tasks ... Total time: 12.02 secs $ gradle --daemon tasks ... Total time: 2.52 secs
とこんな感じです。すごいですね。 jpsしてみると
$ jps 9376 Jps 4136 GradleDaemon
とデーモンプロセスが常駐してるのが分かるはず。
あと--daemon
オプションが付けられていようが、--no-daemon
というオプションを追加すれば、デーモンは無視して自前プロセスで実行できたりします。
デーモンプロセスありきでalias設定してあっても、一時的にはずせるわけですね。
また、デーモンプロセスが要らなくなったら、普通にkill
コマンドでもいいですが--stop
オプションを使えばgradleコマンド経由でコントロールできます。
個人的にはGradle Wrapperを優先しつつDaemonは必須で使いたいので、以下のようなaliasをシェルで設定して使っています。
gradle='if [ -x ./gradlew ]; then GRADLE_BIN=./gradlew; else GRADLE_BIN=\gradle; fi; $GRADLE_BIN --daemon'
こちらも詳しくはユーザガイド(日本語)をどうぞ。
ちなみにGroovyServもビルドにGradleを使っていて、Daemon様におかれましては大変お世話になっております。
GroovyServとGradle Daemonの違い
Gradle Daemonは、Gradleタスクの起動処理をショートカットする GroovyServは、Groovyスクリプトの起動処理をショートカットする
Gradle Daemonは、gradleコマンドのオプションですべて操作する GroovyServは、groovyclientコマンドのオプションで操作するほかに、サーバプロセス起動用のgroovyserverコマンドがある
Gradle Daemonは、ユーザの気付かないうちにデーモンプロセスが常駐してる GroovyServは、サーバプロセスの起動時にコンソール出力してアピールする
気の利いた大喜利風にオチがつけばいいのですが、実力的に無理でした。ごめんなさい。
結局、コンセプト的なものは一緒ですけど、用途が違うので細かいところで色々と違いますね。 あんまりまじめに比べるモノじゃないと思われます。 むしろGroovyServと比べるべきはNailgunとかDripあたり。
おまけ: NailgunとGroovyServの違い
Nailgunはよく知られたJVMプロセス常駐系アーキテクチャのツールです。 歴史的にはGroovyServよりも古いです。 古すぎて2005年以降はまったく更新されていません。 と思ったら、2012/11月にv0.9.1がリリースされててちょっと驚きました。
NailgunはピュアJava実装なのでビルトイン目的によく使われます。 というかAPI的にもそれっぽい感じ。 JRubyもNailgunを使ってますね。
GroovyServはGroovyで実装してるのでビルトイン目的には向いてません。
GroovyServは今更ピュアJava路線に変更するのは不可能ではないにしろ面倒つらい感じです。
ビルトインの代わりに、単にクライアントの引数でmainクラスのエントリポイントを指定するだけで色々なJVM言語の起動時間短縮を計れます。物は言いようです。
機能的な違いでいえば、下のような感じです。
- GroovyServのみサポート
- 両方ともサポート
- System#exit()が実行されてもJVMは落ちない
ほらこうやってみるとGroovyServ結構がんばってるでしょ? Nailgun側のメリットはビルトイン以外に思いつきませんが、他に何かあるかもしれません。 フェアじゃないのは単に知識不足です。すいません。
おまけ: DripとGroovyServの違い
Dripはシンプルで割り切ったアーキテクチャで中々興味深いところはありますが、アーキテクチャやサポート機能が違いすぎてGroovyServとはあまり競合しないふいんき。
簡単に言うと、
http://b.hatena.ne.jp/nobeans/20130904#bookmark-109556574
GroovyServのようなJVMプロセス常駐系/興味深いアプローチ/単一プロセスを使い回すとdirtyになっていくのでJVM引数,クラスパス,起動クラスのハッシュごとに異なるJVMデーモンを使う/コードベースが超小さい/bash限定は楽そう
という感じです。
Dripは、bashを前提にしているので色々実装がシンプルです。うらやましいです。 GroovyServは、Mac/Linux/Windowsで動作します。 現状ではWindowsサポートが若干手薄な気もしますが、次期バージョンではできるだけ環境ごとの機能差がないように頑張っています。
Dripは、カレントディレクトリ毎に別プロセスを起動します。 よって、複数プロセスが常駐します(一定時間でタイムアウトして消える)。 既存JVMプロセスに対するネイティブレベルでのCWD制御とかを不要にしたりしてます。割り切り方が素敵です。 GroovyServは、ポート毎に1つのサーバプロセスを用意しています。 普通はデフォルトポートで十分なので、サーバプロセスは1つだと思えばOKです。ある意味シンプル。 CWDなどは毎回力業で反映しています。
こんな感じでしょうか。
測定マシンについて一言
なお、上記記事中の性能的なものはすべて自宅の超古いMacbook 2008 Midで測定してます。 そうとう遅いです。 苦痛です。 今晩のAppleのイベントで新MBPでたら速攻で買い換えたい所存です。
まとめ
というわけで、GVMを使ってGradleをインストールしたら、ついでに
$ gvm install groovy $ gvm install groovyserv
すると良いと思います。 更に手が滑って
$ gvm install gaiden
とGaidenのインストールまで進んだあなたはファッションリーダとしての自覚と風格が感じられて頼もしい限りです。