Sunday, December 16, 2012
Multiple Dispatch in Modern JVM Languages
GREE engineers' blog に投稿しました: Multiple Dispatch in Modern JVM Languages
Wednesday, May 9, 2012
InvokedynamicでGroovyライフをリスタートしよう
Groovyは5/7にリリースされたバージョン2.0 beta 3でinvokedynamic (indy)に対応しました。これはindyであなたのGroovyライフをリスタートする方法をお見せするだけの短い投稿です。Indyはダイナミックなメソッド呼び出しのためのJava SE 7の新たなバイトコード命令です。もしあなたがindyについて知らないのであればJSRを読んでください。
さぁ、では始めましょう。まずはindyに対応したバージョンのGroovyをインストールしてください。現時点(2.0 beta 3)ではindyはデフォルトで対応されていないためです。次のいずれかの方法が選べます。
* アーカイブをダウンロードしてlib/内のgroovy.jarあるいはembeddable/内のgroovy-all.jarの代わりにindy/にあるgroovy-indy.jarかgroovy-all-indy.jarを使う。
* indyを有効にするオプションを使ってソースからビルドする
ant install -DuseIndy=true -DskipTests=true
2番目に、あなたの目的に応じた方法で次のようにindyを有効にするオプションを付けてコンパイルします:
* groovy
groovy --indy YourScript.groovy
* groovyc
groovyc --indy YourScript.groovy
* GroovyShell class
import org.codehaus.groovy.control.CompilerConfiguration def conf = new CompilerConfiguration() conf.optimizationOptions.indy = true def shell = new GroovyShell(conf) shell.evaluate(/* your script */)
これだけです! それでは良いGroovyライフを!
Friday, May 4, 2012
Exploring JavaFX 2 - アプリケーションパラメタへのアクセス
JavaFXはApplicationクラスオブジェクトからアプリケーションパラメタにアクセスする方法としてApplication.getParameters()を提供します。例えば、ユーザがGNU形式でオプション(名前付きパラメタ)に幅と高さ、引数(名前なしパラメタ)にメッセージを指定すれば:
java AccessApplicationParametersDemo --width=200 --height=100 helloアプリケーションは次のようにパラメタを受け取れます:
public class AccessApplicationParametersDemo { public static void main(String[] args) { Application.launch(UsingGetParametersApplication.class, args); } }
public class UsingGetParametersApplication extends Application { @Override public void start(Stage stage) throws Exception { Map但しgetParameters()は今のところ(v2.2-b06)オプションのパーサが貧弱で使い勝手がよくありません。省略オプションやPOSIX形式に対応してなく、次の形式のどれも扱えません:opts = getParameters().getNamed(); System.out.println("width=" + opts.get("width")); System.out.println("height=" + opts.get("height")); List args = getParameters().getUnnamed(); System.out.println("message=" + args.get(0)); } }
-w=200 -h=100
--width 200 --height 100
-w 200 -h 100getParemters()をカスタマイズすればいいでしょうか?しかし実装クラスへのアクセスが中でハードコードされていて、メソッドがfinalだと聞いたらどうでしょう?つまりgetParameters()から直接オプションや引数を取得するのは今のところ良い選択ではありません。getParameters()には運搬役に徹してもらい、主な作業はApache Commons CLIに任せるのがお勧めです:
public class UsingCommonsCliApplication extends Application { @Override public void start(Stage stage) throws Exception { Options options = new Options(); options.addOption("w", "width", true, ""); options.addOption("h", "height", true, ""); CommandLineParser parser = new PosixParser(); CommandLine cmd = parser.parse( options, getParameters().getRaw().toArray( new String[getParameters().getRaw().size()] ) ); System.out.println("width=" + cmd.getOptionValue("width")); System.out.println("height=" + cmd.getOptionValue("height")); System.out.println("message=" + cmd.getArgList().get(0)); } }この問題に対するJavaFXチームからの回答は"将来のバージョンでは検討可能"ということなのでそのうち解消されるかもしれません。そもそもこのような機能はパラメタを固定された形式で受けとるAppletやJWSでのみ必要とされるはずなので、JavaFXはAppletApplicationやJWSApplicationのような各環境用のクラスを持ち、それらにのみこの機能を持たせる方が良さそうです。
Tuesday, March 20, 2012
正しいGroovyベンチマーク
GroovyのようなJVM上に乗っている言語のベンチマークは難しく、安易に行うと誤った結果を出すことになります。例えばStringBuilderとStringBufferの比較するため次のようなプログラムを書いたとします。StringBufferは同期の為にStringBuilderよりも遅いことがよく知られています:
しかし期待とは異なりStringBufferがStringBuilderよりも2倍以上も速い結果になりました(Groovy 1.8.6、JVM 1.7.0_04-ea Server VM)。最適化により同期のコストがなくなったとしても同等以下のはずであり、この計測は完全に失敗しています:
StringBuilder同士で比較すれば失敗はより明らかとなります:
何が問題だったのかは実行時間の推移を見るとわかります。1回目の計測中に最適化が行われ、2回目は最適化がある程度完了した状態から開始されています。そのため1回目は2回目より不利となります。また、2回目の計測中に飛び出ている数値があります。これはガベージコレクションによるものですが、この時に回収されるゴミは1回目の計測中に出たものを含みます。この点では逆に2回目が1回目より不利となります。つまり正しいベンチマークとは同じスタートラインに立たせることであり、そのためには計測前に最適化を完了させメモリを掃除しゴミ箱を空にしておく必要があります。
これらの問題を自身で解決するのもよいですが、幸運なことにGroovyにはベンチマークフレームワーク、GBenchがあります。GBench 0.3.0はあなたに代わってこれらの面倒な課題を解決し正しい結果を出す機能を持っています。GBenchを使って書き直したのが次のコードです。measureCpuTimeをfalseにしCPU時間の計測を無効にすると実行時間のみの簡潔なレポートを受け取れます:
このコードの実行結果は次のようになりました。差がそれ程ないのは私の環境がServer VMであり、ロック周りが最適化される為です。ロックの最適化ついてはJeroen Borgersの記事、Java 6のスレッド最適化は実際に動作しているのか?が参考になります:
最適化を無効にした(-XX:-DoEscapeAnalysis -XX:-EliminateLocks -XX:-UseBiasedLocking)結果は以下のとおりでした:
def n = 100 * 1000 def at, bt bt = System.nanoTime() n.times { def sb = new StringBuilder() sb.append('foo') sb.append('bar') sb.append('baz') } at = System.nanoTime() println((at - bt) / n) bt = System.nanoTime() n.times { def sb = new StringBuffer() sb.append('foo') sb.append('bar') sb.append('baz') } at = System.nanoTime() println((at - bt) / n)
しかし期待とは異なりStringBufferがStringBuilderよりも2倍以上も速い結果になりました(Groovy 1.8.6、JVM 1.7.0_04-ea Server VM)。最適化により同期のコストがなくなったとしても同等以下のはずであり、この計測は完全に失敗しています:
StringBuilder 1947.3 (2.76) StringBuffer 703.1 (1)
StringBuilder同士で比較すれば失敗はより明らかとなります:
StringBuilder #1 2030.68 (4.85) StringBuilder #2 418.47 (1)
何が問題だったのかは実行時間の推移を見るとわかります。1回目の計測中に最適化が行われ、2回目は最適化がある程度完了した状態から開始されています。そのため1回目は2回目より不利となります。また、2回目の計測中に飛び出ている数値があります。これはガベージコレクションによるものですが、この時に回収されるゴミは1回目の計測中に出たものを含みます。この点では逆に2回目が1回目より不利となります。つまり正しいベンチマークとは同じスタートラインに立たせることであり、そのためには計測前に最適化を完了させメモリを掃除しゴミ箱を空にしておく必要があります。
これらの問題を自身で解決するのもよいですが、幸運なことにGroovyにはベンチマークフレームワーク、GBenchがあります。GBench 0.3.0はあなたに代わってこれらの面倒な課題を解決し正しい結果を出す機能を持っています。GBenchを使って書き直したのが次のコードです。measureCpuTimeをfalseにしCPU時間の計測を無効にすると実行時間のみの簡潔なレポートを受け取れます:
import gbench.* new BenchmarkBuilder().run(measureCpuTime:false) { 'StringBuilder' { def sb = new StringBuilder() sb.append('foo') sb.append('bar') sb.append('baz') sb.toString() } 'StringBuffer' { def sb = new StringBuffer() sb.append('foo') sb.append('bar') sb.append('baz') sb.toString() } }.prettyPrint()
このコードの実行結果は次のようになりました。差がそれ程ないのは私の環境がServer VMであり、ロック周りが最適化される為です。ロックの最適化ついてはJeroen Borgersの記事、Java 6のスレッド最適化は実際に動作しているのか?が参考になります:
StringBuilder 244 (1) StringBuffer 265 (1.08)
最適化を無効にした(-XX:-DoEscapeAnalysis -XX:-EliminateLocks -XX:-UseBiasedLocking)結果は以下のとおりでした:
StringBuilder 242 (1) StringBuffer 310 (1.28)
Subscribe to:
Posts (Atom)