読者です 読者をやめる 読者になる 読者になる

GroovyServとGradle Daemonとの違い

groovy groovyserv gradle

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のインストール」と書いてたので、親切心でコメントしたわけです。

そこまでは良かったのですが、ちょっと調子に乗ってしまいまして、

と書いたところ、記事に晒し上げされてしまいました。 なんということでしょう。

f:id:nobeans:20131022224044p:plain

そのままフェードアウトしてくれれば終わればまだ良かったのですが、自称怖くないモンスターの人に見付かって問い詰められている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のみサポート
    • アクセス元アドレスと認証トークンを使ったアクセスコントロール
      • 許可されたアドレス以外のマシンからのコマンド実行はエラー
      • 同一マシンでも認証トークンが一致しないとコマンド実行はエラー
    • クライアント側のCLASSPATH環境変数をサーバ側に一時的に反映する
    • クライアント側の任意の環境変数をサーバ側に永続的に反映する(一時的反映がベストであるが現状は永続的)
    • クライアント側のカレントディレクトリをサーバ側に一時的に反映する
    • クライアント側のCtrl-Cでサーバ側の処理を中断する
  • 両方ともサポート
    • 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のインストールまで進んだあなたはファッションリーダとしての自覚と風格が感じられて頼もしい限りです。

標準バンドルのVisualVMのウィンドウが空っぽになってしまったらキャッシュを削除すべし

java

経緯的な

9月にTwitterにぼやいた件のその後。

事象

事象としては、jvisualvmを起動するとこんな画面になって何もできないというもの。

f:id:nobeans:20131017135555p:plain

Netbeansプラットフォームアプリケーションの素のウィンドウだけ表示してみました的な感じで、メニューバーも本来のVisualVMとは違ってまっさらな感じ。 かろうじてVisualVM臭がするのはAboutダイアログぐらいです。 ホントになにもできません。

http://visualvm.java.net/download.html からダウンロードしたApp版のVisualVMは普通に動きます。

ちなみに、Macです。他のOSで発生するかは知りません。

解決策

VisualVMのキャッシュが壊れていたようです。 /Users/me/Library/Caches/VisualVM/7u14を削除してから起動したら、正常に動作しました。

ちなみに、7u40や7u45にバンドルされてるjvisualvmを使っても、ディレクトリ名は7u14でした。 なんででしょうね。

本家Grailsユーザガイドを開くと自動的に日本語翻訳にリダイレクトするChrome拡張

grails

Grailsユーザガイド日本語翻訳版とブックマークレットの紹介 - 豆無日記で、紹介したブックマークレットを毎回実行するのがダルすぎるので、Chrome拡張にしてみました。

以下のURLからChrome拡張をインストールしてください。

セキュリティの都合から野良サイトからの直接インストールはできないようなので*1、いったんダウンロードしてから拡張の管理画面にドラッグ&ドロップするとよいでしょう。

これで、http://grails.org/doc/latest/*なサイトを開くと自動的にhttp://grails.jp/doc/latest/*にリダイレクトされるようになります。 これでGoogle検索結果からのリンクでもさくっと日本語版が表示できますね。

コードという程のモノではない何かはGitHubにサラしてあります。

*1:https://support.google.com/chrome_webstore/answer/2664769?p=crx_warning&rd=1

Grailsユーザガイド日本語翻訳版とブックマークレットの紹介

有志によるGrailsユーザガイドの日本語翻訳作業がずっと行われていたのですが、実は8月の頭にちょうど一区切り良い感じになりました。 そろそろリリースされそうなGrails 2.3向けに追記された部分などまだちょっと英語部分も残っていますが、基本機能についてはほぼすべて翻訳完了な感じです。

残念なことに検索しても出てくるのは本家の英語版だけだったりすることが多いです。

URLのドメイン部分がgrails.orggrails.jpと違うだけなので、ブラウザのアドレスバーを手作業で書き換えて日本語版を表示させたりして過ごしていますが、さすがに面倒になってきたのでブックマークレットを書いてみました。

  • タイトル例
    • Grailsユーザガイドを日本語化する
  • URL
    • javascript:location.href=location.href.replace(/grails.org/,'grails.jp')

そのまんまですが、わりと便利な感じなのでよかったらどうぞ。

iPhotoライブラリをDropboxで管理するときに気をつけるべきたったひとつのこと

iPhoto Libraryの中にあるOriginal、Data、Modifiedというエイリアスを削除してから共有しましょう。

なんで?

Dropboxエイリアス経由のパスであっても気にせずに物理的にサーバ上にファイルを格納するので、画像が多重にアップロードされてしまい、サーバ利用量がヤバいことになります。というか、なった。

具体的にはどうする?

iPhoto Libraryを右クリックのアレで開いて、Original、Data、Modifiedというエイリアスを削除しましょう。Data.noindexというのがあったらそれも*1iPhotoはこれらがなくても普通に動作しますが、万が一何かあっても自己責任でお願いします。

経緯

元々20GBも使ってないときに、40GBくらいのiPhoto Libraryを共有したら、アップロードに2〜3日かかったあと、合計で105GB使ってますよという状態になってしまったので、有料会員の特権(?)でサポートに問い合わせてみたら、FAQらしくて手順書ページを紹介されました。 対処後に一晩放っておいたら、無事に60GBぐらいに落ち着いて、サイズ保存則が無事に成立しました。

*1:自分はなかった

Gradle1.6の新機能mustRunAfterでタスク間の実行順序が制御可能になった #gradle

gradle

Gradleではタスク間の依存関係の指定ができます。

build.gradle:

task a << {
    println "A"
}
task b(dependsOn: "a") << {
    println "B"
}
task c(dependsOn:"a") << {
    println "C"
}
task d(dependsOn: ["b", "c"]) << {
    println "D"
}

実行結果:

$ gradle d
:a
A
:b
B
:c
C
:d
D

BUILD SUCCESSFUL

Total time: 1.612 secs

実はこの例のBとCの間の関係は不定であり、実装に基づいて(この場合はアルファベット順だったりしたはず)実行順序が決められます。 ここではA→B→C→Dになっていますね。

しかし、このようなグラフ的には一見どっちがさきに実行されても良いようにみえるBとCの間に、実は微妙な前後関係があって、Cの方が先に実行されて欲しい!というケースは意外とありますよね。

長い間Gradleユーザから臨まれていたこの機能がついに1.6で実装されました(ということをさっき知った)!

Task#mustRunAfter()の使い方

以下のように使います。

build.gradle:

task a << {
    println "A"
}
task b(dependsOn: "a"/*, mustRunAfter: "c" -- 残念ながら今のところここには書けないらしい*/) {
    mustRunAfter "c" // メソッド呼出として書く
    doLast {
        println "B"
    }
}
task c(dependsOn:"a") << {
    println "C"
}
task d(dependsOn: ["b", "c"]) << {
    println "D"
}

と書くと、こうなります:

$ gradle d
:a
A
:c
C
:b
B
:d
D

BUILD SUCCESSFUL

Total time: 1.64 secs

dependsOnとの違い

実は単にA→C→B→Dとしたいだけであれば、↓と書くだけでもOKです。

task a << {
    println "A"
}
task b(dependsOn: ["a", "c"]) << {
    println "B"
}
task c(dependsOn:"a") << {
    println "C"
}
task d(dependsOn: ["b", "c"]) << {
    println "D"
}

mustRunAfterとの違いは、タスクbを実行してみると見えてきます。 一つ前のサンプルだと:

$ gradle b
:a
A
:c
C
:b
B

BUILD SUCCESSFUL

Total time: 0.723 secs

となります。 bの依存先にcが入ってるので実行タスクのグラフにcが登場するのですね。

さて、mustRunAfterを使った先ほどと同じこの設定で実行してみると...

task a << {
    println "A"
}
task b(dependsOn: "a") {
    mustRunAfter "c"
    doLast {
        println "B"
    }
}
task c(dependsOn:"a") << {
    println "C"
}
task d(dependsOn: ["b", "c"]) << {
    println "D"
}

実行結果:

$ gradle b
:a
A
:b
B

BUILD SUCCESSFUL

Total time: 1.745 secs

となります。 mustRunAfterは依存関係の指定ではなく、実行タスクのグラフ上にそのタスクが存在した場合に単にその順序関係を指定しているだけなので、この場合にはタスクcは登場しないのです!

実際どういう場面で使うの?

ふもさんのサンプルがわかりやすそうです。

task clean << {
  println 'cleaning.'
}
task build << {
  println 'building.'
}
build.doLast {
  println 'finish!'
}
task local(dependsOn: [clean, build]) << {
  println 'local debug.'
}

これを実行するとこうなります:

$ gradle local
:build
building.
finish!
:clean
cleaning.
:local
local debug.

BUILD SUCCESSFUL

Total time: 1.638 secs

buildしてからcleanするとかso crazyですね。ちょっと何言ってるか分からないです。

ここで実行順序制御にdependsOnを使おうとすると、

task clean << {
  println 'cleaning.'
}
task build(dependsOn: 'clean') << {
  println 'building.'
}
build.doLast {
  println 'finish!'
}
task local(dependsOn: [clean, build]) << {
  println 'local debug.'
}

実行結果:

$ gradle local
:clean
cleaning.
:build
building.
finish!
:local
local debug.

BUILD SUCCESSFUL

Total time: 1.605 secs

うまくいった!?ようにみえますが、cleanせずに差分ビルドさせようとbuildタスクを指定すると...

$ gradle build
:clean
cleaning.
:build
building.
finish!

BUILD SUCCESSFUL

Total time: 0.755 secs

cleanまで発動してしまいました!!これでは毎回フルビルドになってしまい、開発速度が上がりません。

そこで、mustRunAfterの出番です。

build.gradle:

task clean << {
  println 'cleaning.'
}
task build {
  mustRunAfter 'clean'
  doLast {
    println 'building.'
  }
}
build.doLast {
  println 'finish!'
}
task local(dependsOn: [clean, build]) << {
  println 'local debug.'
}

実行結果:

$ gradle local
:clean
cleaning.
:build
building.
finish!
:local
local debug.

BUILD SUCCESSFUL

Total time: 0.722 secs
$ gradle build
:build
building.
finish!

BUILD SUCCESSFUL

Total time: 1.58 secs

素晴らしい!期待通りの結果です。

というわけで、依存関係のdependsOnと、実行順序の微調整のmustRunAfterをうまく使い分けましょう。

コペンハーゲンのGR8Conf EU 2013でGroovyServとImproxプラグインを紹介してきた

https://pbs.twimg.com/media/BLDRxqACQAE4lf1.jpg

5/22-24にデンマークはコペンハーゲンで開催されたGR8Conf EU 2013というGroovy系のカンファレンスで、GroovyServImproxプラグインを紹介してきました。

右の写真はコペンハーゲンの定番がっかり観光スポットの「人魚の像」ですね。 がっかり感が軽減されている一枚を選びました。 まあ、どこの観光地にもがっかりスポットはつきものです。 札幌の時計台にくらべれば人魚はだいぶ良かったんじゃないでしょうか。

GR8Conf EUは今年で5周年だそうです。コペンハーゲンがオリジナルですが、「GR8Conf」ブランドのカンファレンスは別ロケーションでも何度か開かれていて、USは今年も7月にありますしほぼレギュラー化してるようですね。他に覚えているところではオーストラリアでも開催されてました。日本でも開きたいですね。

さて、自分の発表ですが、本日動画が公開され(てしまっ)たので、スライドと動画のリンクを張っておきます。 つたない英語ですがよければご笑覧ください。

当方の深刻な英語力不足にともない今回は不本意ながら「最初に言い訳」メソッドで乗り切りましたが、やっぱりせっかくやるからには「ネイティブ&インタラクティブ」方式を目指したいですね。 最後、質疑がなくて寂しい感じにみえますが、たぶんみなさん気を遣ってくれた感じで、セッション後に数名の方と技術的な話もしましたからね? *1

他の錚々たるスピーカのみなさんの動画も随時公開されていくはずなので、興味がある方はTwitter@gr8confをフォローしておくと良いと思います。

そうそう、今度の6/21のJGGUG主催GワークショップZで、G*ワークショップZ Jun 2013 - GR8Conf報告&ライブコーディング&GroovyServ/Improxをやります。 ご興味があれば是非是非ご参加ください。

*1:どちらかというと「お前の英語は悪くない」「問題ないよ」「グレートだったぞ」みたいな慰めにきてくれた人の方が多かったですけど。