ラベル JJUG の投稿を表示しています。 すべての投稿を表示
ラベル JJUG の投稿を表示しています。 すべての投稿を表示

2024/12/02

Valueクラスによる最適化
 で、ValhallaのValue Classってどうなったの? その2

このエントリーをはてなブックマークに追加

本エントリーはJava Advent Calendarの2日目です。昨日はHatanoさんのこんにちは、世界でした。

 

さて、前回のエントリーに続き、Project ValhallaのValue Classについて紹介していきます。

本エントリーでは、Value Classを使用した場合に可能になる最適化について説明します。

 

前回のエントリーで紹介したようにValue Classの導入の背景にあったのが、ヒープ使用効率の最適化にあります。

そこで説明したのが、配列の領域に参照ではなく、直接データを埋め込む手法です。この最適化を平坦化(Flattering)と呼ぶようです。まずは、この平坦化から紹介していきましょう。

 

なお、Value Classはまだ策定中の仕様なので、今後変化する可能性があります。本エントリーで説明していることも変わる可能性が高いので、その点はご了承ください。

 

平坦化

Value ClassのオブジェクトをIdentityオブジェクトと同じようにヒープに配置するのではなく、Valueオブジェクトをフィールドとして持つオブジェクトのフィールド領域に埋め込んでしまうのが平坦化です。

前回は配列で説明しましたが、value record Point(double x, double y){}のような小さなValue Classであれば、その配列であるPoint[]にPointオブジェクトが保持すべきxとyを直接埋め込むこと最適化が可能です。

とはいっても、配列なんか使わないからなぁ... と思いますよね。

配列ではなくてリストで平坦化してくれればと思いますよね。でも、ほとんどの場合、リストといえばArrayListクラスを使っているはず。

ArrayListクラスのArrayは配列のこと。ArrayListクラスが内部で保持している配列が平坦化できれば恩恵は大きいはず。

ただ、ArrayListクラスが内部で保持しているのはObjectクラスの配列なのが気になります。今のジェネリクスは、型パラメータで指定された型の配列を作成することができません。

これができれば、平坦化することも可能なはず。というようなことをProject Valhallaの人たちが考えていないわけがないので、今後何らかの進展があると予想しているのですが、どうなんでしょうね。

また、平坦化は配列以外にも適用されます。たとえば、以下のようなレコードはどうでしょう。

value record Point(double x, double y) {}
    
record Rectangle(Point topLeft, Point bottomRight) {}

 

RectangleレコードクラスはValueクラスのPointオブジェクトを2つフィールドに保持します。Valueクラスであれば、フィールドに参照を保持させるのではなく、直接値を保持できるようになります。

さらにRectangleレコードクラスがValueクラスであれば... というように考えていくこともできるはずです。

ただし、平坦化が常に行われるとは限りません。Value ClassがPreview機能で提供されたとしても、当初は最適化される部分は少ないはずです。リリースが進むにつれ、徐々に最適化の範囲が増えていくことが予想されます。

 

スカラー化

もう1つの最適化がスカラー化(Scalarized)です。スカラー化というと多目的計画法で使う言葉だと思っていたのですが、JVMの最適化でも使うんですね。

それはそうとして、以下のようなコードを考えてみます。

    record Score(int score) {}
    
    record Adder(int sum) {
	Adder() { this(0); }

	Adder add(int v) {
	    return new Adder(sum + v);
	}
    }

    int calcTotal(List<Score> scores) {
	Adder adder = new Adder();

	for (var s: scores) {
	    adder = adder.add(s.score());
	}

	return adder.sum();
    }

 

通常は意識しないとは思いますが、Javaのコードはjavacコンパイラでバイトコードに変換され、JVMはバイトコードを実行します。

バイトコードの実行にはスレッドごとにJava Stackという特殊なスタックが作成されます。スタックにはメソッドごとにフレームが積まれます。このフレームにはオペランドスタックというスタックとローカル変数用の領域を持っており、これらを利用してバイトコードを実行します。

オペランドスタックは実行中の状態を保持させるスタックで、演算やメソッドコールはこのオペランドスタックに積まれた値に対して行われます。

ローカル変数領域も実際に使用する時には、オペランドスタックにロードし、処理の結果は再びローカル変数領域にストアされます。

ローカル変数領域もプリミティブ型の値であれば直接保持されますが、参照型の値の場合はヒープに存在するオブジェクトへの参照が保持されます。

つまり、上記のcalTotalメソッドの場合、scores変数はListオブジェクトへの参照、adder変数はAdderオブジェクトへの参照が保持されるわけです。

このcalcTotalメソッドのバイトコードは以下のようになります。

  int calcTotal(java.util.List<Score>);
    descriptor: (Ljava/util/List;)I
    flags: (0x0000)
    Code:
      stack=2, locals=5, args_size=2
         0: new           #7                  // class Adder
         3: dup
         4: invokespecial #9                  // Method Adder."<init>":()V
         7: astore_2
         8: aload_1
         9: invokeinterface #10,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        14: astore_3
        15: aload_3
        16: invokeinterface #16,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
        21: ifeq          48
        24: aload_3
        25: invokeinterface #22,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        30: checkcast     #26                 // class Score
        33: astore        4
        35: aload_2
        36: aload         4
        38: invokevirtual #28                 // Method Score.score:()I
        41: invokevirtual #32                 // Method Adder.add:(I)LAdder;
        44: astore_2
        45: goto          15
        48: aload_2
        49: invokevirtual #36                 // Method Adder.sum:()I
        52: ireturn

全体を解説することはしませんが、注目していただきたいところは色付きにしました。

オレンジの0から7の行はAdderオブジェクトを生成して、ローカル変数の[2]に保存しているバイトコードになります。

インデックス0にはthis、インデックス1には引数のListオブジェクトの参照が保持されており、その後にAdderオブジェクトの参照が保持されるわけです。

赤で示した35から44がJavaのコードでいうところのforループの内部の処理に当たります。

aload_2でローカル変数[2]からAdderオブジェクトの参照をオペランドスタックに積み、次のaloadでローカル変数[4]をスタックに積んでいます。このインデックス4には、Scoreオブジェクトの参照が保持されています。

その後の38のinvokevirtualがコメントにあるようにScoreクラスのscoreメソッドをコールしています。その結果はそのままスタックに積まれます。この時点でスタックにはAdderオブジェクトとscoreメソッドの戻り値のint値が積まれています。

そして、41のinvokevirtualでAdderクラスのaddメソッドをスタックに積まれたint値を引数にコールします。addメソッドの戻り値は新たに生成されたAdderオブジェクトで、スタックに積まれるので、44のastore_2でローカル変数[2]に保存されます。

 

 

このように、forループの内部では毎回Adderオブジェクトを生成し、ローカル変数のオブジェクト参照を更新するということを繰り返します。また、そのオブジェクトが保持している値はやはり毎回アクセスする必要があります。

毎回のオブジェクト生成や、値の取得処理が省略できるのであれば、パフォーマンが向上します。

もし、メソッド内で使用していたオブジェクトが、戻り値などでメソッドの外に逃げ出さないのであれば、この最適化をすることができます。

メソッドから逃げ出さないというのは、当該メソッド以外の部分でオブジェクト参照するということです。オブジェクトにどこから参照されるか分からないので、たとえValueオブジェクトであっても通常のIdentityオブジェクトと同じようにヒープにオブジェクトを配置しなければなりません。

逆に、オブジェクトがメソッド内だけで使われるのであれば、Valueオブジェクトをヒープに作るのではなく、Valueオブジェクトが保持する値をローカル変数領域に直接保持させてしまえばいいわけです。

 

 

ローカル変数領域に値を直接保持させることで、オブジェクト生成や参照の張替えが不要になります。

繰り返しになりますが、この最適化はValueオブジェクトがメソッド内にとどまっていることが条件になります。このため、オブジェクトがメソッド内だけで使用されているかどうかを調べる必要があります。

これをエスケープ解析(Escape Analysis)と呼びます。オブジェクトがメソッドの外に逃げ出さないかどうかを解析するということですね。エスケープ解析でオブジェクトが逃げ出さないと分かれば、スカラー化以外にも最適化が可能になります。

 

ここでは2種類の最適化を紹介しましたが、Valueクラスが提供された時にはじめから両方の最適化が行われるとは限りません。まずはValueクラスを使えるようになり、そこから徐々に最適化が導入されていくことが予想されます。

また、最適化を行うにはエスケープ解析でオブジェクトが逃げ出さないことが条件になりますが、他にもいくつか条件があります。その1つにnullの扱いがあります。

たとえば、Valueオブジェクトが保持する値にnullが紛れてしまうと、平坦化もスカラー化もできなくなってしまいます。

このため、Project Valhallaでは、null非許容性とnull許容性、つまりNon-NullとNullableを導入することになりました。

Non-NullとNullableは以前から要望がありましたが、まさかProject Valhallaによって仕様策定されることになるとは思いもよりませんでした。

そこで、次のエントリーではNon-Null/Nullableと、それに関連してオブジェクト初期化処理の変更について紹介する予定です。

2023/07/04

JJUG Java仕様勉強会 「Javaの並列/並行処理の基本」

このエントリーをはてなブックマークに追加

6/29にJJUGのJava資料勉強会で並列/並行処理についてプレゼンしてきました。資料はこちら。

 

Javaの並列/並行処理についてですが、Virtual Thread以前の仕様に関してまとめた感じです。

Javaの並列/並行処理のAPIはjava.util.concurrentパッケージ、いわゆるConcurrency Utilitiesにまとめられており、それほどいっぱいあるわけではないです。ただ、使う上でのノウハウ的なものがいっぱいあるので、言語仕様やAPIの仕様とは離れますが、そのノウハウ的なものもさわりだけ紹介しました。

 

Threadの基本

Javaで並列/並行処理を行う時に必ず使うことになるのが、Threadクラスです。

ThreadクラスはOSスレッドのラッパーであり、ThreadオブジェクトとOSスレッドは1対1に対応しています。ただし、Java 21で導入されるVirtual ThreadはJVMが管理する軽量スレッドなので、OSスレッドとは直接結びつきません。

このセッションでは、Virtual Threadについては触れないので、Threadと行った時はOSスレッドに結びついている従来のThreadをあつかいます。なお、この従来からあるThreadをVirtual Threadと区別するためにPlatform Threadと呼びます。

 

並列処理と並行処理という2つの言葉がありますが、Javaの世界からはこの2つは区別されません。使用できるCPUのコアが少なく、それに対しスレッドが多く存在する場合は並列(Concurrent)として実行されます。一方で、コアが十分にあるのであれば、並行(Parallel)として処理されます。

つまり、同じThreadクラスで書いておけば並列にも並行にも処理されることがあるということです。

そして、Threadオブジェクトに対して行う操作は、OSスレッドに対する操作になります。

 

Threadを使う上で意識しなければいけないのが、Threadのライフサイクルと、Threadの実行順序(スレッドスケジューリング)です。

Threadのライフサイクルとは、生成から廃棄まで。

new演算子でThreadオブジェクトを生成するとOSのスレッドも作成されます。このこともあって、Threadオブジェクトの生成には時間もかかりますし、メモリ使用量も大きくなります。

一方のスレッドスケジューリングはどのような順番でスレッドを実行するかを決めます。使用できるコア数がスレッドよりも少ない場合、どこかでスレッドの切り替え(コンテキストスイッチ)が発生します。

コンテキストスイッチも時間もかかり、メモリも多く使用する処理です。このため、初期のJavaではなるべくコンテキススイッチが発生しないようにスケジューリングされていました。

しかし、プログラム内でThread.yeildやObject.waitなどが使用されると、コンテキストスイッチが発生します(本当にコンテキストスイッチを行うかどうかはスケジューラーが決めます)。頻繁なコンテキストスイッチはパフォーマンス劣化の原因になります。

このようなことから、スレッドの生成/廃棄の管理や、スレッドスケジューリングはなるべくJVM側で管理させ、私たち開発者は非同期に処理されるタスクを記述することに注力すべきです。

そこで、登場したのがConcurrency Utilitiesというわけです。

 

Conccurency Utilities

Conccurency Utilitiesが導入されたのはJava 5。2004年なので、もう20年近く前です。当時はマルチコアのCPUがようやく出てきたころで、ParallelよりはConcurrentの時代です。

Concurrency Utilitesが提供しているのは大別して次の4種類のAPIです。

  • 非同期タスクの実行・管理
  • 並列コレクション
  • アトミック操作
  • ロック

この時は非同期タスクの実行・管理に絞って説明しました。

非同期タスクの実行・管理に関する主なインタフェースとクラスは以下の4種類だけです。

  • ExecutorService: 非同期タスクの実行
  • Executors: ExectuorServiceのファクトリ
  • Runnable/Callable: 非同期タスク
  • Future: 非同期タスクの管理

Executorsだけがクラスで、他はインタフェースです。

他にもExecutorインタフェースやFutureTaskクラスなどがありますが、直接使うことは稀です。

ExecutorsクラスはExecutorServiceオブジェクトのファクトリメソッドを定義したクラスです。主に使われるファクトリメソッドは

  • newFixedThreadPool
  • newChacedThreadPool

の2メソッドです。いずれもスレッドを使いまわすスレッドプールを提供するExecutorServiceオブジェクトを生成します。

newFixedThreadPoolメソッドは固定のスレッド数だけでスレッドプールを作成します。スレッド数は引数で指定します。どちらかというと非同期タスクの応答性を重視したスレッドプールになります。

一方のnewCachedThreadPoolメソッドで生成するスレッドプールは、必要に応じてスレッドを生成するスレッドプールです。もし、使われていないスレッドがあれば使いまわします。こちらはスループット重視型のスレッドプールです。

他にもシングルスレッドで動作するnewSingleThreadExecutorメソッドや、タイマーなど周期的なタスク実行を行うためのnewScheduledThreadPoolメソッドがあります。

また、Java 8で、後述するWork-Stealingを使用したスレッドプールを提供するnewWorkStealingPoolメソッドが追加されました。次のJava 21ではVirtual Threadを使用するnewVirtualThreadPerTaskExecutorメソッドも提供される予定です。

 

ExecutorServiceインタフェースは非同期タスクの実行を行うためのインタフェースです。どのようにタスクの実行を行うかは実装クラスによって異なります。

基本的には使用するメソッドは2種類だけです。

  • Future<T> submit(Callable<T> task)
  • Future<T> submit(Runnable task, T result)
  • Future<T> submit(RUnnable task)
  • void close()

タスクの実行を行うのがsubmitメソッドです。タスクがCallableインタフェースかRunnableインタフェースの違いでオーバーロードが3種類あります。

closeメソッドはJava 19で追加されたメソッドです。なぜ今ごろになってcloseメソッドが追加されたかというと、try-with-resources構文が使えるようになったからです。

これまではshutdownメソッドもしくはshutdownNowメソッドを使う必要がありましたが、これからはtry-with-resourcesですね。

また、複数のタスクをまとめて登録できるinvokeAllメソッドとinvokeAnyメソッドもありますが、これらのメソッドは結果がでるまでブロックします。このため、ちょっと使いにくいメソッドでした。

Virtual Threadの導入に合わせてStructured Concurrencyが提案されており、invokeAll/invokeAnyメソッドはこちらに置き換えられていくと思います。ただ、Java 21ではまだPreview JEPなので、次の次のLTSに間に合うぐらいです。

 

さて、非同期タスクを記述するのがRunnableインタフェース/Callableインタフェースです。

両者の違いは戻り値があるかないかだけと思っている方が多いと思いますが、もう1点大きな違いがあります。

それは、RunnableインタフェースのrunメソッドはChecked Exceptionをスローできないのですが、Callableインタフェースのcallメソッドはできるという点です。

このため、Runnableインタフェースを使う場合、例外をスローさせるにはRuntime Exceptionでくるんでスローするしかありませんでした。しかも、Runtime Exceptionがスローされると、その例外はUncaught Exceptionとして扱われ、スレッドは何も言わずに死んでしまうのです。

UncaughtExceptionHandlerが登録してあれば検知できますが、それでも直接例外が発生したことは分かりません。

これに対し、CallableインタフェースであればChecked Exceptionもスローできます。また、例外が発生した場合、FutureインタフェースのgetメソッドなどでExecutionException例外としてcatchすることができます。

 

最後がFutureインタフェースです。

FutureインタフェースはExecutorServiceインタフェースのsubmitメソッドの戻り値になり、submitメソッドで登録した非同期タスクの管理を行います。

型パラメータはタスクの戻り値の型です。Runnableインタフェースを使用した場合はFuture<?>となります。

主に使うメソッドは

  • T get()
  • cancel()
  • Future.State state()

ぐらいでしょうか。

一番使うメソッドは、タスクの結果を取得するgetメソッドだと思います。ただ、getメソッドは結果が出るまでブロックすることに注意が必要です。

cancelメソッドはタスクのキャンセルのためのメソッドです。ただし、cancelメソッドでキャンセルできるかどうかは、タスクの書き方に依存します。

stateメソッドはJava 19で追加されたメソッドで、それまではisDone/isCancelledメソッドで状態を調べていました。stateメソッドを使うことで、もう少し詳しく状態を調べることができます。

Java 19では、resultNowメソッドとexceptionNowメソッドも追加されました。

この2つのメソッドはブロックをしないのですが、タスクが完了していないとIllegalStateException例外がスローされます。

 

後半は非同期タスクの書き方。

非同期タスクを書く上で安全性とスケーラビリティが重要になります。並列度が低い時代には安全性が重視されていましたけど、現在のように多くのコアが使えるようになるとスケーラビリティが重要になってきます。

ようするにスレッドセーフなクラスであったとしても、スケールできないものは使いものにならないわけです。とはいうものの、安全性がないがしろにされていいわけではありません。

安全性を確保しつつ、スケールするタスクを記述する必要があります。

まぁ、言うのは簡単ですけど、実際に書くのはむずかしいですね。

 

おまけでFork/Join FrameworkとCompletableFutureについても紹介しました。

特にFork/Join Frameworkは開発者が直接使うことはほぼないと思うので、使いかたよりも動作原理について紹介しました。

また、CompletableFutureは関数を連ねて処理を記述できる人であればとても使いやすいAPIなのですが、例外が扱いにくかったり、デバッグが難しいという点もあります。Virtual Threadであれば、例外やデバッグが容易になるので、書きやすい方で書けばよいと思います。

2023/06/18

JJUG CCC 2023 Spring

このエントリーをはてなブックマークに追加

2019年からずっと登壇してなかったのですが、久しぶりにJJUG CCCで登壇することになりました。

 

今回のお題はVirtual Threadsです。

話の流れなどは、今年の1月に行われたブリ会議で話したことをベースにしています。ただ、ブリ会議が20分のセッションだったのが、CCCでは45分なので、コンテンツ的にはかなり変更してあります。

 

前半はVirtual Threads導入の背景、後半がVirtual Threadsの使い方になっています。

なぜ今になってVirtual Threadsが導入されたかというのは、歴史的経緯があるので、そこをちゃんと抑えましょうということです。

というのも、Virtual Threadsの目的はスループット向上なのですが、現状の技術でスループットは向上できるからです。たとえば、CompletableFutureやリアクティブ系のライブラリやフレームワークを使えばスループットは向上できます。

これらの技術を使いこなせればいいのですが、なかなか難しい点もあります。たとえば、

  • 関数を連ねて処理を記述するので、従来とは考え方を変えなければならない
  • 例外処理が難しい
  • デバッグが難しい

最初の考え方は慣れてもらうしかないのですが、最後のデバッグはなかなか難しい問題です。というのも、処理が複数のスレッドに分割して実行されるので、スタックトレースが切れてしまうからです。

スタックトレースはスレッドごとに存在するので、スレッドをまたがって処理を行えば当然スタックトレースは分割されてしまいます。それがデバッグを難しくしてしまいます。

そういう問題を解決するのがVirtual Threadsというわけです。

 

とはいっても、Virtual Threadsは今までのスレッドと使い方が同じなので、特にこうしましょうというのはないです。

サーバー系のシステムでリクエストに応じてスレッドをよしなに作ってくれるようなフレームワークを使っているのであれば、なおさらVirtual Threadsを意識する必要はないです。

というわけで、そういうフレームワークがVirtual Threadsに対応してくれるのを待ちましょうというのが結論ですw

フレームワークがVirtual Threadsに対応したら、何もしなくてもスループットが向上するかもしれません。

というようなことをセッションで話したら、今週になってTomcatがVirtual Threadsに対応したというじゃないですか。

Tomcatでさえ対応したのだから、他のフレームワークもVirtual Threadに対応するのは意外に早いかもしれません。

 

ただし、Virtual Threadsに限らず並行処理で注意する点というのもあります。

並行処理で重要になるのは、安全に処理できるかということと、スケールするかどうかということです。しかも、この両者はなかなか両立しません。

同期化やロックなどを使用して安全な処理を記述すると、その部分はスケールせずに並列処理のボトルネックになってしまいがちです。

特にVirtual Threadsを使い始めると、スレッド数が今までとは桁違いに多くなるため、スケールできるかというのは重要になります。

では、どうすればいいか。

設計を見直して、synchronizedを使った同期化をなるべく減らしていくしかありません。そのためには、イミュータブルなデータをベースに考えるようにすればいいと思います。特にJava 16で導入されたRecord型が役に立つはずです。

どうしてもsynchronziedが外せない処理があるのであれば、そこはロックAPIのReentrantLockに書き換えましょう。というのも、synchronizedを使用するとVirtual Threadsが動作するOSのスレッドをブロックしてしまうためです。

ReentrantLockであれば、ブロックするのはVirtual Threadsだけになります。

というようなことを45分で喋ってきました。あまりにも、ギリギリまで喋ってしまったので、質疑応答の時間が取れなくなってしまいました。ごめんなさい。

 

当日は気持ちの余裕がなくて、あまり他のセッションは聞けなかったのですが、ちょっとした感想を書いておきます。

 

Apache Commons Math を使って、機械学習をやってみた

浅野さんの機械学習のセッション。といっても、扱っているの古典的なクラスタリングのk-means。

k-meansぐらいならライブラリ使わなくても、自力で書けるぐらいですね。というか、書いたことがありましたww

やっぱりPythonと比べると記述量が多くなってしまうのはしかたないですね。でも、OpenCVSとか使えば、もうちょっと減らせると思います。

 

浅野さんが列挙してくれた機械学習系のライブラリの1つにWekaがあるのですが、これは使ったことがありました。

でも、Wekaはソースがひどいんですよねぇ...

アルゴリズムをそのままコードに落とした感じで、読みやすさとかそういうのはまったく考慮してない感じ。まぁ、大学で作ってるし、しかたないんですけどね。

 

AI を利用した Java 開発の最新情報

てらださんのOpenAI系のお話なんだけど、なんだかなぁ...

てらださん、もうちょっとプレゼンのしかた考えようよ...

 

Java Bytecode Crash Course

もともとChristoph Engelbertさんのセッションだったのですが彼が体調不良ということで、急遽David Buckさんのセッションに差し替え。

バイトコードの読み方入門的な内容でした。内容的にはほとんど知っていることでしたが、やっぱりこういうのはおもしろいよね。人を選ぶとは思いますがw

 

今回のJJUG CCCは現地開催でストリーミングありでしたが、なかなか大変そうでした。コストもかかるしね。

今回ストリーミングで見ていただいた方も、次回はぜひ現地でお会いしましょう!

2023/06/17

JOnsen 2023

このエントリーをはてなブックマークに追加

コロナのおかげで開催できなかったJOnsenですが、4年ぶりに6月1日から2泊3日の日程で開催されることになりました。なお、今回からJJUGが主催のイベントになっています。

JOnsenは温泉に入りながらJavaについて語り合うアンカンファレンスで、今回で4回目の開催です。

第1回から参加しているさくらばは、当然今回も参加することにしました。

 

今回の開催場所はリゾナーレ八ヶ岳。参加人数は13人で、ちょっと少ないです。まぁ、コロナがあって、こういうイベントに参加するのを躊躇してしまう人も多いと思うので、しかたないですね。

 

初日

初日のスタートは14時から。他の参加者はみなお昼ぐらいに到着して、ランチを食べてから参加という感じですが、私だけちょっと早く現地入りしました。というのも、リゾナーレ内にあるマルサマルシェというフルーツパーラーでパフェ作り体験ができるからなのでした。

事前に予約しておいて、Bigパフェを作ってきました。

平日ということもあって、リゾナーレは未就学児を連れた家族連ればかり。パフェ体験も子供たちと一緒に作っている人たちばかりで、おじさんが1人で作っているなんて私だけですよw

下の写真のようにフルーツとパフェグラス渡されます。後は、冷蔵庫にあるホイップクリームとコンフィチュール、またコーンフレークやスプリンクルなどは使い放題です。

_DSC8361

事前にいろいろ考えてきたのですが、実際にパフェを作るのなんてはじめてなので、悪戦苦闘。ホイップクリームだけでなく、せめてジュレがほしかった...

ということで、パフェできました!

_DSC8402

 

さて、JOnsenの本編です。

会場はリゾナーレのイスキアという普段は宴会などに使われる場所です。

だいたいの日程は初日の午後と、2日目の午前、最終の午前にアンカンファレンス。2日目の午後はアクティビティを行うというものです。

ただ、2日目は台風の接近に伴う大雨の予定。雨でなければ乗馬などのアクティビティもあったのですが、急遽インドアのアクティビティになることになりました。

で、パフェ作りの人気が高いww さすがに2日連続でパフェというのも変なので、私はトンボ玉作成にしました。

_DSC8541 _DSC8546

 

アクティビティを決めた後に、まずは全員の自己紹介タイム。そして、アンカンファレンスで議論するトピック出しと続きます。最低でも1人1トピック。

トピックを付箋に書き出したら、各々トピックの説明を行います。もちろん、全部英語です。

_DSC8582 _DSC8584

付箋はホワイトボードに貼りだして、似ているトピックをグルーピング。その後、どのトピックを議論するかの投票です。

_DSC8639

実際に提案されたトピックがこちら。丸いシールが投票された票です。

_DSC8666

人気があったトピックからディスカッションしていきます。

今回は、人数も少ないので2グループに分けて、だいたい一方が技術的なトピックで、もう一方がコミュニティや働き方などの非技術的なトピックになっていました。

さくらばは結局、全部技術的なトピックの方に参加してました。

 

ディスカッションは写真のように丸テーブルで。そんなに固い感じではなく、緩い感じで。それにしても、久しぶりの英語だったので、ぜんぜん英語が出てこない。やっぱり日ごろから練習していないとダメですね。

_DSC8670 _DSC8686

 

そういえば、Steve Chinさんが車で参加予定だったのですが、いろいろと遅れて、1日目のディカッションの最後にやっとあらわれました。とりあえず、無事についてよかったです。

 

1日目のディナーはリゾナーレ内のイタリアン。なかなか本格的なイタリアンでした。

_DSC8714 _DSC8791 _DSC8819 _DSC8834

 

ディナー後にまたどこかで集まって飲んだりするのかなぁと思ったら、何もなく。みんな疲れたのか、そのまま就寝してしまいました。

でも、さくらばはJJUG CCC用の資料が終わってなかったので、泣く泣く資料作成。CCCの前のJOnsenはつらい...

 

2日目

朝からあいにくの雨。

朝ごはんはリゾナーレ内のYY Grillのビュッフェ。平日ということもあって、未就学児を連れたファミリーが多いです。

朝からしっかり食べましたよ。しかも、ここには自由に使えるソフトクリーマーがあるので、朝からソフトクリーム。

でも、ソフトクリームが固すぎて、うまく巻けませんでした...

_DSC8929 _DSC8935 _DSC8958

朝ごはんは同室のDavid Buckさんと行ったのですが、彼は実際にJavaを作っている人。しかも、HotSpotを作っているのです!

ちょうどJJUG CCCでVirtual Threadについてプレゼンするので、自分がVirtual Threadに関して考えていたことを聞いてもらい、間違いがないか確かめてもらいました。

この朝のセッションが、JOnsenで一番役に立ったかもしれませんw

 

さて、2日目の午前中はアクティビティの時間。

というわけで、トンボ玉を作る場所へ向かってみると... なんと今日はトンボ玉を作る先生がお休み!

他にも作る系のアクティビティは先生が休みのところ多くて、行き場を失った私たちは結局パフェの人たちを冷やかしにいくことに。

と思ったら、急にキャンセルが出たらしくテーブルが空いていたので、急遽クレープ作り体験ができることになりました!

とはいっても、クレープはすでに焼いてあって、それを飾り付けする感じです。

それにしても、普段はお客の大半がファミリーの店で、大人がほぼ占拠しているというのはなかなかレアな感じですね。ちなみに、私は店員さんにしっかり覚えられていましたw

_DSC8962 _DSC8970 _DSC8993 _DSC9003 _DSC9005 _DSC9012

それぞれ、パフェとクレープを作ってから、三々五々とランチへ。

私は、やはりリゾナーレ内にあるジビエの店で鹿肉バーガー。竹炭入りの黒いバンズというのはなかなかインパクトありますね。

_DSC9035 _DSC9045

 

さて、午後のアンカンファレンスも昨日と同じように2グループに分かれて行います。だいたい1つのトピックで40~50分ぐらい。

今日はProject CRaCや、関数型についてなどのディスカッションに参加。

Project CRaCは全然知らなかったのですが、起動時間を短縮させるためのプロジェクトなんですね。Graalのネイティブイメージとの比較などが議論の中心でした。

_DSC9117 _DSC9119 _DSC9129 _DSC9138

 

2日目のディナーはリゾナーレのすぐそばにあるジビエの八ヶ岳小僧という店。

店主が自ら狩りを行って、季節、季節のジビエを食べさせてくれるのだそうです。

で、私は鹿、猪、熊の盛り合わせと、鹿ユッケ。ご飯はたけのこご飯です。

鹿や猪は食べたことありますけど、熊ははじめて。脂がうまいww

_DSC9164 _DSC9188 _DSC9180 _DSC9208

 

最終日

最終日、朝ごはんを食べに行った時はまだパラパラと雨が降ってましたが、食べ終わったことろには晴れてきました。

そして、この日もソフトクリーム。昨日よりはうまく巻けたとは思いますが、やっぱり硬くてやりにくい...

_DSC9253

 

最終日のディスカッションは1トピックだけで、その後はラップアップ。

最後のディスカッションはVirtual Threadに関してですが、自分的には昨日の朝のDavidさんとの議論で話したいことを話してしまったのでしたw

Virtual Threadの技術的なこともそうですが、BrianのJava並行処理プログラミングの本が絶版で困るようねぇとか。本が売れないから再販もないだろうねぇとか。

_DSC9282 _DSC9278 _DSC9266 _DSC9275

そして、最後のラップアップで、ディスカッションのまとめを各々が発表する感じです。

_DSC9293 _DSC9306 _DSC9308 _DSC9326

 

JOnsenは全部英語なのでなかなかつらいのですが、それでも日本人ばかりなのでスピードはゆっくり。

ネイティブの人たちばかりだとスピードも速いし、話している間もかぶせてくるので、なかなか議論に参加するだけでもたいへん。その点、JOnsenはゆったりしているし、ちゃんと意見を言い終わるまで待ってくれるし、英語でのディスカッションに慣れていない身としては、とてもありがたいです。

今年はいつものメンバーになってしまったのはしかたないですけど、来年はぜひ他の人も参加してほしいなぁ。

というわけで、最後に記念写真を撮っておしまい。

_DSC9333

2015/04/10

JJUG Night Seminar "Raspberry Pi Night Seminar"

このエントリーをはてなブックマークに追加
2015.04.10 JJUG Night Seminar "Raspberry Pi Night"

明日は CCC なのですが、基調講演をしてもらう予定の Stephen Chin さんが Raspberry Pi のイベントをやってくれるということで、急遽開催することになりました。

私は受付業務。もうちょっと誰か来てくれるかと思ったら、誰も来てくれなくて JJUG の幹事は私だけ。Oracle の伊藤さんが手伝ってくれたので、どうにかなりましたが...

今回はほんとにデモだけです。明日の基調講演でデモする予定のものや、その他のデモを比較的ゆっくりとお見せすることができたのではないかと思います。

そして、お子さんが多かったのが、今回の特徴でした。デモを見るだけだったら、プログラミング技術は必要ないし、英語の勉強にもなるので、ちょうどよかったのかもしれません。

とはいうものの、中には実装の説明がないことにがっかりして、帰られてしまった方もいらっしゃいました。主催者側もどういう内容になるか当日までちゃんと把握できていなかったことが、問題だったと思っています。デモだけだと分かっていれば、イベントページにもその諭旨が記載できたはずでした。

それでも、ほとんどの参加者に楽しんでいただけたようでよかったです。

2015.04.10 JJUG Night Seminar "Raspberry Pi Night"
2015.04.10 JJUG Night Seminar "Raspberry Pi Night"
2015.04.10 JJUG Night Seminar "Raspberry Pi Night"
2015.04.10 JJUG Night Seminar "Raspberry Pi Night"
2015.04.10 JJUG Night Seminar "Raspberry Pi Night"
2015.04.10 JJUG Night Seminar "Raspberry Pi Night"
2015.04.10 JJUG Night Seminar "Raspberry Pi Night"