Slide 1

Slide 1 text

Java 5.0時代の非同期処理技術から学び直す Scala/Java 非同期処理 マーベリック株式会社 リチャード 伊真岡

Slide 2

Slide 2 text

現代のアプリケーション開発は 非同期処理が重要

Slide 3

Slide 3 text

モバイルアプリケーションでの 同時多発的な処理

Slide 4

Slide 4 text

処理がまずいと...

Slide 5

Slide 5 text

サーバー側でも様々な処理を 同時に行う

Slide 6

Slide 6 text

ZIO CatsEffect Monix Future Akka チュートリアルを見れば それっぽい物は書ける... Finagle

Slide 7

Slide 7 text

今日のながれ • 抽象度の低いものから高いものへと少しずつ学ぶ • Java5.0からの歴史を学ぶ、各技術の背景とつながりを学ぶ

Slide 8

Slide 8 text

マルチスレッド Multi-threaded Concurrent Asynchronous 平行 非同期 用語について

Slide 9

Slide 9 text

マルチスレッド Multi-threaded Concurrent Asynchronous 平行 用語について このスライドでは「非同期」という単語をよく使うが 平行・マルチスレッド処理でもある物が中心 非同期

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Java Memory Model と Java 5 の非同期処理

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

Oracle Concurrency guide https://docs.oracle.com/javase/tutorial/essentia l/concurrency/ 今日一番覚えておいて ほしい資料!!!

Slide 15

Slide 15 text

Thread & Runnable public class MyRunnable implements Runnable { public void run() { ... } } Thread thread = new Thread(new MyRunnable()); thread.start();

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

java.util.concurrent (Java 5.0 以降)

Slide 18

Slide 18 text

ExecutorService ExecutorService service = …; service.execute(runnable);

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

非同期で起こる問題の一例

Slide 23

Slide 23 text

thread interference (非atomic処理) class Counter { private int c = 0; public void increment() { c++; } public void decrement() { c--; } public int value() { return c; } }

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

1. Thread A: int c 取得 2. Thread B: int c 取得 3. Thread A: 取得した値をIncrement 4. Thread B: 取得した値をDecrement 5. Thread A: cに1を書き込み 6. Thread B: cに-1を書き込み (6が5を上書き)

Slide 27

Slide 27 text

synchronized class Counter { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--; } public int value() { return c; } }

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

synchronized atomic happens-before

Slide 32

Slide 32 text

happens-before

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

data race (memory-consistency error)

Slide 37

Slide 37 text

順番(happens-before)があれば 期待される状態を導ける

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

少なくともどちらか一方が writeである場合 conflicting access data race (問題) の原因

Slide 40

Slide 40 text

Java Memory Model Java 5.0 (1.5) からの導入 https://www.cs.umd.edu/~pugh/java/memoryModel /jsr133.pdf http://gee.cs.oswego.edu/dl/jmm/cookbook.html http://www.cs.umd.edu/~pugh/java/memoryModel/

Slide 41

Slide 41 text

非同期処理の理論的な研究 Java Memory Modelは当時の学術 的な非同期処理研究にもとづい て作られている。

Slide 42

Slide 42 text

Java 5.0ではSynchronizedの他にも data raceを避けるツールが導入された

Slide 43

Slide 43 text

java.util.concurrent.locks Lock ReadWriteLock Condition ReentrantLock ...

Slide 44

Slide 44 text

volatile “write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable” volatile int counter = 0;

Slide 45

Slide 45 text

atomic java.util.concurrent.atomic AtomicInteger AtomicBoolean AtomicLong AtomicReference ... //CAS operation boolean compareAndSet(expectedValue, updateValue); CASはCPUでサポートされた操作 java.util.concurrent.atomicはそれを利用する

Slide 46

Slide 46 text

 1.CAS成功例

Slide 47

Slide 47 text

 2.CAS成功例

Slide 48

Slide 48 text

 3.CAS成功例 memory location value == expected

Slide 49

Slide 49 text

 1.CAS失敗例

Slide 50

Slide 50 text

 2.CAS失敗例

Slide 51

Slide 51 text

 3.CAS失敗例 memory location value != expected

Slide 52

Slide 52 text

thread-safe collections java.util.concurrent ConcurrentHashMap ConcurrentLinkedQueue ... CASを利用

Slide 53

Slide 53 text

● Java Memory Model 仕様 ○ happens-before ○ volatile, synchonized, locks ● java.util.concurrency ツール ○ locks, atomic, ExecutorService, thread-safe collections ○ これらをうまく使うパターン、抽象度の更に高いツールは後年 Java 1.4 -> 5.0 時代のまとめ

Slide 54

Slide 54 text

ここまでの話は後でくり返し出てきます!

Slide 55

Slide 55 text

OSとCPU

Slide 56

Slide 56 text

Netflixのパフォーマンス分析エンジニア Brendan Gregg氏が2013年に書いた CPUやメモリの動作がOSレベルでどう使わ れているかについて参考になる章がある http://www.brendangregg.com/sysperfbook.html

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

CPUとキャッシュ Stack Exchange - Where exactly L1, L2 and L3 Caches located in computer? https://superuser.com/questions/1961 43/where-exactly-l1-l2-and-l3-caches-loc ated-in-computer キャッシュは「スレッド ごとのメモリ空間」に関 わる -> data race -> happens-before

Slide 59

Slide 59 text

CPUとキャッシュ Stack Exchange - Where exactly L1, L2 and L3 Caches located in computer? https://superuser.com/questions/1961 43/where-exactly-l1-l2-and-l3-caches-loc ated-in-computer キャッシュは「スレッド ごとのメモリ空間」に関 わる -> data race -> happens-before data race (memory-consistency error)

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

同時に走るスレッドは 高々CPUコア数

Slide 64

Slide 64 text

同時に走るスレッドは 高々CPUコア数

Slide 65

Slide 65 text

同時に走るスレッドは 高々CPUコア数

Slide 66

Slide 66 text

同時に走るスレッドは 高々CPUコア数

Slide 67

Slide 67 text

GUIとThread

Slide 68

Slide 68 text

A Swing programmer deals with the following kinds of threads: ● Initial threads, the threads that execute initial application code. ● The event dispatch thread, where all event-handling code is executed. Most code that interacts with the Swing framework must also execute on this thread. ● Worker threads, also known as background threads, where time-consuming background tasks are executed. スレッド使用例 Swing guide UI framework (Java 5.0以前から使われていた) https://docs.oracle.com/javase/tutorial/uiswing /concurrency/index.html

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

BrowserのEvent Loop

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

event loop

Slide 76

Slide 76 text

event loop

Slide 77

Slide 77 text

main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(b); } function funcA(a) { return funcB(a); } funcA(“my user data string”); call stack event loop

Slide 78

Slide 78 text

funcA() main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(b); } function funcA(a) { return funcB(a); } funcA(“my user data string”); call stack event loop

Slide 79

Slide 79 text

funcB() funcA() main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(c); } function funcA(a) { return funcB(a); } funcA(“my user data string”); call stack event loop

Slide 80

Slide 80 text

funcB() funcA() main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(b); } function funcA(a) { return funcB(a); } funcA(“my user data string”); funcC() call stack event loop

Slide 81

Slide 81 text

funcB() funcA() main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(c); } function funcA(a) { return funcB(a); } funcA(“my user data string”); funcC() call stack event loop ajax コール

Slide 82

Slide 82 text

funcB() funcA() main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(c); } function funcA(a) { return funcB(a); } funcA(“my user data string”); call stack event loop

Slide 83

Slide 83 text

funcB() funcA() main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(c); } function funcA(a) { return funcB(a); } funcA(“my user data string”); call stack event loop

Slide 84

Slide 84 text

funcA() main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(c); } function funcA(a) { return funcB(a); } funcA(“my user data string”); call stack event loop

Slide 85

Slide 85 text

main() function funC(c) { … //make an ajax call } function funcB(b) { return funcC(c); } function funcA(a) { return funcB(a); } funcA(“my user data string”); call stack event loop

Slide 86

Slide 86 text

function funC(c) { … //make an ajax call } function funcB(b) { return funcC(c); } function funcA(a) { return funcB(a); } funcA(“my user data string”); event loop ajax コールバック タスクキュー

Slide 87

Slide 87 text

タスクキューも含めたアニメーション

Slide 88

Slide 88 text

ajax コール

Slide 89

Slide 89 text

ajax コールバック

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

関数型プログラミングと immutable object

Slide 94

Slide 94 text

少なくともどちらか一方が writeである場合 conflicting accessは data race (問題) の原因

Slide 95

Slide 95 text

Java Memory Model でもdata raceは主要な関心事 https://www.cs.umd.edu/~pugh/java/memoryMod el/jsr133.pdf http://gee.cs.oswego.edu/dl/jmm/cookbook.html http://www.cs.umd.edu/~pugh/java/memoryModel/

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

No content

Slide 98

Slide 98 text

オブジェクトを変更する際は新しいインスタンス を作成、元のオブジェクトはそのまま

Slide 99

Slide 99 text

Oracle Concurrency guide もimmutable objectに 言及している ● setterダメ ● final, private ● ...

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

Akkaとactor model

Slide 102

Slide 102 text

rich, realtime -> 状態 ?

Slide 103

Slide 103 text

IDを持つオブジェクトの内部状態が変化する例

Slide 104

Slide 104 text

IDでクエリ

Slide 105

Slide 105 text

IDでクエリ

Slide 106

Slide 106 text

IDを持つオブジェクトのインスタンスが 複数スレッドに存在する場合

Slide 107

Slide 107 text

どのスレッドに対して クエリ?

Slide 108

Slide 108 text

デーモンスレッドにオブジェクトのインスタンスを保持

Slide 109

Slide 109 text

デーモンスレッドにオブジェクトのインスタンスを保持

Slide 110

Slide 110 text

デーモンスレッドにオブジェクトのインスタンスを保持

Slide 111

Slide 111 text

No content

Slide 112

Slide 112 text

クエリはできたしかし...

Slide 113

Slide 113 text

少なくともどちらか一方が writeである場合 conflicting accessは data race (問題) の原因

Slide 114

Slide 114 text

conflicting accessはの正しい管理は難しい

Slide 115

Slide 115 text

conflicting accessはの正しい管理は難しい

Slide 116

Slide 116 text

shared mutable: 複雑さの元凶 shared mutable: おもしろさの源

Slide 117

Slide 117 text

アプリケーションの状態をすべて データベースで管理する方法

Slide 118

Slide 118 text

データベース周りの ソースコードが複雑

Slide 119

Slide 119 text

複雑さのバランスを アプリケーション側 との間でとる

Slide 120

Slide 120 text

オブジェクトの内部状態

Slide 121

Slide 121 text

Actorでオブジェクトの内部状態を隠蔽

Slide 122

Slide 122 text

Actorどうしはメッセージを送り合って通信

Slide 123

Slide 123 text

Akka actorコードサンプル actor ! message class MyActor extends Actor { var state = ... def receive = { case MessageTypeX => ... case MessageTypeY => ... case MessageTypeZ => ... } }

Slide 124

Slide 124 text

SenderはReceiverのスレッドセーフなキューに メッセージを送る

Slide 125

Slide 125 text

No content

Slide 126

Slide 126 text

複数Senderから同時に メッセージを送ることが可能

Slide 127

Slide 127 text

Akka actorのメッセージキューは デフォルトで ConcurrentLinkedQueue

Slide 128

Slide 128 text

Akka actorのメッセージキューは デフォルトで ConcurrentLinkedQueue

Slide 129

Slide 129 text

Akka actorのメッセージキューは デフォルトで ConcurrentLinkedQueue

Slide 130

Slide 130 text

Receiver側の動作を追っていく

Slide 131

Slide 131 text

No content

Slide 132

Slide 132 text

単一のスレッドがReceiverの receiveメソッドを走らせる スレッド1 スレッド2

Slide 133

Slide 133 text

スレッド1 スレッド2 Receiverはキューから一つずつ メッセージを取り出し処理する

Slide 134

Slide 134 text

スレッド1 スレッド2 Receiverの実行スレッドは 入れ替わることがある

Slide 135

Slide 135 text

ActorのReceiveメソッドは いかなる時も最大一つのスレッド によって実行 スレッド0 スレッド1 スレッド2

Slide 136

Slide 136 text

スレッド0 スレッド1 Receiverはキューからメッセージ がなくなったら次を待つ

Slide 137

Slide 137 text

Akka official documentation https://doc.akka.io/docs/akka/current/general/jmm. html#actors-and-the-java-memory-model 自分でvolatileを使う 必要はない Akkaが面倒を見てくれる ActorのReceiveメソッドは いかなる時も最大一つのスレッド によって実行

Slide 138

Slide 138 text

No content

Slide 139

Slide 139 text

volatile “write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable”

Slide 140

Slide 140 text

> さらにvolatileな変数をreadす るとき、read側のスレッドは最 新のvolatile変数の変更のみなら ず、そこへ至るまでのコードの 副作用まで観測することになる Oracle concurrency guide

Slide 141

Slide 141 text

akkaのDispatcherは内部で ExecutorServiceへの参照を持つ akkaの ! メソッドはDispatcher のdispatchメソッドの内部で ExecutorServiceのexcecuteメ ソッドを呼ぶ するとThread Poolに対して Actorのreceiveメソッドをスケ ジュールする Dispatcher Thread Pool ExecutorService dispatch() execute()

Slide 142

Slide 142 text

Akka actor modelまとめ ● shared mutableは難しいが重要な場合がある ● actor modelはshared mutable管理の一つの解 ● AkkaはJava 5.0時代からのツールを内部で使う

Slide 143

Slide 143 text

関数型方面の近年の進化

Slide 144

Slide 144 text

Scalaで非同期処理を主要機能に含むライブラリ Scala標準 Monix Cats Effect ZIO

Slide 145

Slide 145 text

共通なパターン

Slide 146

Slide 146 text

Cats Effect SemaphoreやMVarなどの 低レベルな非同期処理の パーツを acquire, releaseなどの コンビネータとともに定義 https://typelevel.org/cats-effect/

Slide 147

Slide 147 text

Cats Effect 安全に非同期処理の低レベ ルなbuilding blockを実装

Slide 148

Slide 148 text

Cats Effect Scalaのfor文とモナドを組 み合わせるテクニックに よってChainingを実現 型安全なので各処理ステッ プの戻り値型とエラー型が 合わなければコンパイラが エラーで教えてくれる https://typelevel.org/cats-effect/

Slide 149

Slide 149 text

https://typelevel.org/cats-effect/

Slide 150

Slide 150 text

https://typelevel.org/cats-effect/ Swing GUI Event Dispatcher Background Threads Main Thread

Slide 151

Slide 151 text

https://typelevel.org/cats-effect/ https://typelevel.org/cats-effect/ Event Loop Event Loop Service Worker Web API/File IO

Slide 152

Slide 152 text

https://typelevel.org/cats-effect/ https://typelevel.org/cats-effect/ Akka Default Dispatcher Future on thread pool IO thread pool

Slide 153

Slide 153 text

今話題のEnvoyでもEvent Loopモデルは取り入れられ ている ここまでの話を踏まえれば 比較的容易に理解できるは ず https://blog.envoyproxy.io/envoy-threading- model-a8d44b922310

Slide 154

Slide 154 text

ZIO try/catchブロックを型安全に 行う例 ファイルやデータベースのリ ソース開放に便利 https://zio.dev/

Slide 155

Slide 155 text

ZIO こちらもコンビネータを使って Chainingを行うことができる https://zio.dev/

Slide 156

Slide 156 text

No content

Slide 157

Slide 157 text

No content

Slide 158

Slide 158 text

ZIO fiberもAkka Actorsも 軽量スレッドとしての役割を果 たす。 OSスレッドはメモリ使用量も多 くかつスイッチングコストも高 いので、軽量スレッドのほうが 効率が良い OS Threads Actors OS Threads Fibers Akka ZIO

Slide 159

Slide 159 text

自分の過去 ● 新卒から9年間自社言語: シングルスレッド・同期IOのみ ● Javaの非同期怖かった ● actor modelの実装であるAkkaに興味を持つ

Slide 160

Slide 160 text

非同期処理を楽しく学ぶ ● わかりにくかったら抽象度の低いものを先に学ぶのもアリ ● 今回の発表からひとつだけでも興味を持って欲しい

Slide 161

Slide 161 text

マーベリックではエンジニア募集中

Slide 162

Slide 162 text

文献 https://twitter.com/csgillespie/status/… CPUクロック周波数に関するグラフ付きツイート。 Computer Hope processor history https://www.computerhope.com/history/processor.htm AMDが2005年に初のdual-coreを発売など。

Slide 163

Slide 163 text

Oracle Concurrency guide https://docs.oracle.com/javase/tutorial/… Java 5.0やそれ以前から続く非同期処理技術に詳しい。 Java Memory ModelとJava 5.0 Oracle Concurrency in Swing guide https://docs.oracle.com/javase/tutorial/uiswing/... UIでのスレッド管理プラクティスとして一部今も通用する。

Slide 164

Slide 164 text

The JSR-133 Cookbook for Compiler Writers  http://gee.cs.oswego.edu/dl/jmm/cookbook.html JSR-133に深く関わったDoug Lea教授による情報。 The Java Memory Model  http://www.cs.umd.edu/~pugh/java/memoryModel/ JSR-133仕様書に載っていない周辺情報。 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms https://www.cs.rochester.. ConcurrentLinkedQueue実装に使われたアルゴリズム。 JSR-133 https://www.cs.umd.edu/~pugh/… Java Memory Model仕様書。happens-beforeを始め様々な概 念やコンパイラ最適化の影響などが解説されている。

Slide 165

Slide 165 text

OSとCPU Systems Performance https://www.amazon.com/gp… Netflixのパフォーマンス分析エンジニアBrendan Gregg氏に よる著書。CPUとスレッドについての章がある。 Brendan Gregg’s Home page http://www.brendangregg.com/overview.html Brendan Gregg氏の著書にも関わる様々な情報がある See How a CPU works https://youtu.be/cNN_tTXABUA Scott CPUという教育用の仮想的なCPUを題材に動画で解説 している。

Slide 166

Slide 166 text

GUIとThread The Node.js Event Loop, Timers, and process.nextTick() https://nodejs.org/uk/docs/guides/... 公式ドキュメント。各フェーズ毎の詳細な解説。 GitHub: libuv https://github.com/libuv/libuv/... node.js内部で使われているイベントループの実装を含む非同 期I/Oライブラリ。Cで書かれている。 YouTube: What the heck is the event loop anyway? JSConf https://youtu.be/8aGhZQkoFbQ アニメーションを駆使したevent loop解説。100万再生以上。

Slide 167

Slide 167 text

MDN web docs: Concurrency model and Event Loop https://developer.mozilla.org/en-US/docs/... MozillaによるEvent Loop解説 Akka docs: https://akka.io/docs/ 公式のドキュメント edX: Programming Reactive Systems https://www.edx.org/... AkkaのメンテナであったKonrad Malawski氏が中心となって 作ったオンライン学習コース Akkaとactor model

Slide 168

Slide 168 text

関数型方面の進化(Scala) Monix https://monix.io/ イベント駆動で高パフォーマンスな非同期プログラムを書くサ ポートをするライブラリ。 Cats Effect https://typelevel.org/cats-effect/ I/Oを表す型を提供するライブラリ。同期および非同期の Effectを表現することができる。 ZIO https://zio.dev/ 型安全でcomposableで非同期な処理をかけるライブラリ。

Slide 169

Slide 169 text

YouTube: The Making of an IO - Daniel Spiewak https://youtu.be/g_jP47HFpWA 関数型プログラムと非同期処理の関係を説明。Cats Effectの思想 やスレッドプール使い分けベストプラクティスにも触れる