JJUG ナイト・セミナー「Javaパラレル処理の最前線」に参加してきた。 #jjug
9月17日にJJUG ナイト・セミナー「Javaパラレル処理の最前線」に参加してきました。
申し込み開始の次の日?に申し込んだのですがキャンセル待ち43人目という人気っぷり。
とは言え、大体キャンセルが多く出るので余裕かと思っていたのですが、
開始2時間前になんとかいうギリギリでの参加になりました。
- タイムスケジュール
19:00- 櫻庭祐一さん (@skrb): Legend of Java Concurrency/Parallelism 19:25- 槙俊明さん (@making): そんなリザルトキャッシュで大丈夫か? 19:50- 休憩 20:00- 久保智さん: Java EEでの話(仮) 20:25- きょんさん (@kyon_mm): Groovyで学ぶプロセス代数 20:50- 谷本心さん (@cero_t): LT: Parallel Streamを真面目に勉強してみた話
櫻庭祐一さん (@skrb): Legend of Java Concurrency/Parallelism
- O'Reilly Japan - Javaによる関数型プログラミング
- 桜庭さんおすすめの面白い、いい本らしい。
Javaの歴史
- Java 1.0
- Thread/Runnnable
- synchronized
- volatile
- Object#wait など。
- この時期は処理を切り替えて走らせていたのでコアが遊んでしまう。
- 1.1
- 匿名クラスが書けるようになった。
new Thread()なんて使ってる人いないですよね!
- 1.4
- Mostly Concurrent
- Mark & Sweep GC
- 5
- Async Execution
- Concurrency Utilities
- Executor / ExecutorService
- Runnnable / Callable
- Future
- Synchronizer
- ReentrantLock
- Semaphore
- CountDownLatch
- Threadsafe Collection
- BlockingQueue
- ConcurrentHashMap
- CopyOnWriteArrayList
- Atomic Operation
- AtomicInteger
- AtomicReference
- Async Execution
- 7
- Multi Coreの時代になって、細かいタスクを色んなコアにばらまいて実行する。細かいから同期のコストも小さい。
- ただ、forl/joinは書くのが面倒くさい!
- 8
- Project Lambda
- ParallelStream
- Spliterator
まとめ
- 設計的にはThreadは独立。
- タスクは細かくすることで同期のコストも少なくなる。
槙俊明さん (@making): そんなリザルトキャッシュで大丈夫か?
- デモのコード
- ここでいうリザルトキャッシュ。
- 重い処理の結果を格納するメモリ
たまに見る実装の話
- キャッシュをHashMapに突っ込む。(HashMapはスレッドセーフじゃないので×)
- ConcurrentHashMapに変更する。
- 実はキャッシュをうまく使えてない
- getしてる段階ではまだputされていないので、キャッシュがうまく使えていない
- FutureTaskを使って遅延評価
- とりあえず最初にput。
- 新しいFutureTaskで上書きされた。
- FutureTaskをputする方法は本ではほとんど正解に近いと書かれているが、実際にやってみると全然ダメw
- putではなくputIfAbsentメソッドを使う。
- キーが存在しない場合はnullを、そうでない場合は入っているモノを返す。
- 処理は1回しか行われず、正しくキャッシュされている。
- Java8から
- ConcurrentHashMapのcomputeIfAbsentメソッドが追加。
- Mapに値が入っていなかったらラムダ式を実行する。
まとめ
- ConcurrentHashMap#putIfAbsent + FutureTaskを使う。
- 8からは
- ConcurrentHashMapのcomputeIfAbsentメソッドを使う。
- GoogleのguavaのMapMakerが色々便利らしい。
- JavaEE8のJCash?とかいうのがいいらしい。
20:00- 久保智さん: Java EEでの話(仮)
Java EEの話(仮) from Satoshi Kubo
元はLTで発表した内容と言うことで早かったので内容を適当にまとめ。
- レガシー枠との事。
- Java EEの昔話
- 並行処理でハマった内容
JavaEEの昔の話。
- 並行処理は難しい。
- SingleThreadModel → スレッドセーフになっていない。
- 現在は非推奨
- JavaEEの仕様を決める人でも間違えることがあるので、どんどん失敗しましょう
System.out
- 複数スレッドから同時に書き込むとブロックする
- ログ出力ライブラリを使いましょう
Servletのスコープ
- HttpSessionスコープにはハマる。
- ブラウザ単位で同時にアクセスされる可能性がある。
- アクセス時には安全のためロックしましょう
- ロックできない箇所がある。
- HttoSession#invalidate()
- セッションを破棄するメソッド。
- Tomcatだと実装を直接扱えば破棄されているかを判定するメソッドがある。
JPAのキャッシュ
CDIの非同期処理
- @Asynchronousを付けるだけで非同期処理になる。
- 簡単だけど障害時を考えるとそれでよいのか。
- 簡単に使えるからといってすぐ何でもかんでも使うのではなく、よく考えて使いましょう。
20:25- きょんさん (@kyon_mm): Groovyで学ぶプロセス代数
- CSPというと怖いように思うが、こうやって触っていけばいいんだよね。というようにしたい。
- CSPとは、並行処理のモデルとして利用されているプロセス代数の一例。
- 並行処理関連で「チャネル」が云々とか言われたらCSPかな?って思って聞くといいかも。
- 研究者と実績がたくさん
- Java、Groovyで使用可能。
- 逐次実行と平行実行の比較
- 逐次実行だったらあまり間違わないところでも、平行実行にするだけで難しくなることがよくある。
- FDRというツールで、CSPとほぼ同等の記法のスクリプトを書くと検証してくれる。
- 最初に逐次実行で書いて、並列で書くとどの程度同一か判定してくれる。
- CSPをJava実装したものがJCSPというライブラリとして公開されていて、GParsはJCSPをラップしている。
- Groovyの2.0からGParsは標準で入っている。
- groovyx.gpars.云々パッケージにいい感じにクラスが定義されているのでこれらを使っていく。
- JCSPはもっと色々あるけど、gparsがラップしてるのはこれくらい。
- チャネルを通してでしかプロセス間でやりとりできない。
- 正直、この後の内容は前提知識が足りなくて理解できず。
- コードをたくさん載せてくれているので、動かせばわかるか?(探したけどスライドは公開されていない??TT)
- チャネルは同期的に動作し、プロセスは非同期で動作する。電話みたいなもの(電話かけても相手が受け取らないと始まらない)
- 書籍なんかではFDR2と書かれていますが、現在はFDR3が出ている。
- アカデミックのみ無償。仕事で使う場合はどうすれば?
- ProBなるモノが無償で使えそう?FDR2の時は使えた?
- モデル検査器ProB - 並行システムの検証と実装
- ProB以外にも色々あるみたいだがどれもちょっとイマイチらしい。
- FDRを買いましょう!(数百万?w)
まとめ
- CSPを使ってみるとかいうとハードルが高いけど、Gparsを使うと結構簡単に試せる。
- モデルとコードが近くなりやすいCSPで書いておくとツールでの検証がはかどるし、
- 検証してからコードに書くのも困らない。
- 非同期処理のプロジェクトで失敗したのをキッカケに取り組み始めた。
- 今はCSPベースの何かを開発している!
- CIサーバ、テスティングフレームワーク、ビルドツールとかを作っている!
20:50- 谷本心さん (@cero_t): LT: Parallel Streamを真面目に勉強してみた話
- Java8といえばStream。
- Parallel Streamは面白い!
- StreamAPIをパラレルで行えるのがParallel Stream
- Parallel Streamにしても性能が出ない
- 要素数が少ないと性能がでない
- 10万要素ぐらいを捌かないと効果がないと感じている。
- 落とし穴はいっぱいある
- Parallel Streamは例外時の挙動が予想できない。
- 例外が発生しても、例外が発生したスレッド以外は実行する。
- 例外が発生した時点で割り当てられている処理は行われるが、割り当てられていない処理は実行されない。
- 一回の処理の中では例外が発生しないようにするか、例外をtrycatchして処理するようにしないと、色々ハマる。
- ストリーム内でDBにアクセスするとかありえない。
- それ以前にストリームの外にある変数にアクセスしたらダメ。