非同期処理の歴史から見たコンピューティングの進化

 非同期処理の歴史から見たコンピューティングの進化

14bfbc98a7d5ed3574be08f6b176ce70?s=128

リチャード 伊真岡

August 30, 2019
Tweet

Transcript

  1. 非同期処理の歴史から見たコンピューティングの進化 マーベリック株式会社 リチャード 伊真岡

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

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

  4. 処理がまずいと...

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

  6. JavaScript: promise, async/await Go: goroutine, channel Kotlin: Coroutine Java: java.util.concurrent

    (1.5, 8.0) Scala: Future ReactiveX チュートリアルを見れば それっぽい物は書ける...
  7. 「スレッドセーフじゃなくない?」 そんなときコードレビューで...!! 非同期処理にしたはずが画面フリーズ! エラーが出たけど原因をたどれない... さらにランタイム(本番環境)で...

  8. None
  9. 「非同期おもしろい」と思うキッカケを なにかひとつ見つけてほしい

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

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

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

  13. インターネット・モバイルユーザの増加と CPU性能の変遷

  14. Our World in Data より引用 https://ourworldindata.org/internet 2016年にインターネット ユーザ34億人

  15. Statista より引用 https://www.statista.com/statistic s/263437/global-smartphone-sales-t o-end-users-since-2007/ スマートフォン出荷台数 2018年に15億台 スマートフォン所有者の統 計を見つけられなかった

  16. None
  17. CPUクロック速度の変遷 2005年前後で3.4GHzに 達している https://twitter.com/csgillespie/sta tus/732532249325907968

  18. None
  19. この年表をベースにさらに様々な技術の変遷を 追っていきます 注意) 私はScalaプログラマなので Java, Scalaに関する話が多くなります ただし他の言語でも通用する話が多いです

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

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

  24. Thread & Runnable public class MyRunnable implements Runnable { public

    void run() { ... } } Thread thread = new Thread(new MyRunnable()); thread.start();
  25. None
  26. 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 https://docs.oracle.com/javase/tutorial/uiswing /concurrency/index.html
  27. None
  28. None
  29. None
  30. java.util.concurrent (Java 5.0 以降)

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

  32. None
  33. None
  34. None
  35. 非同期で起こる問題の一例

  36. thread interference (非atomic処理) class Counter { private int c =

    0; public void increment() { c++; } public void decrement() { c--; } public int value() { return c; } }
  37. None
  38. None
  39. 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を上書き)
  40. synchronized class Counter { private int c = 0; public

    synchronized void increment() { c++; } public synchronized void decrement() { c--; } public int value() { return c; } }
  41. None
  42. None
  43. None
  44. synchronized atomic happens-before

  45. happens-before

  46. None
  47. None
  48. None
  49. data race (memory-consistency error)

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

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

  53. 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/
  54. Java 5.0ではSynchronizedの他にも data raceを避けるツールが導入された

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

  56. volatile “write to a volatile variable establishes a happens-before relationship

    with subsequent reads of that same variable” volatile int counter = 0;
  57. atomic java.util.concurrent.atomic AtomicInteger AtomicBoolean AtomicLong AtomicReference ... //CAS operation boolean

    compareAndSet(expectedValue, updateValue); CASはCPUでサポートされた操作 java.util.concurrent.atomicはそれを利用する
  58.  1.CAS成功例

  59.  2.CAS成功例

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

  61.  1.CAS失敗例

  62.  2.CAS失敗例

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

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

  65. • Java Memory Model 仕様 ◦ happens-before ◦ volatile, synchonized,

    locks • java.util.concurrency ツール ◦ locks, atomic, ExecutorService, thread-safe collections ◦ これらをうまく使うパターン、抽象度の更に高いツールは後年 Java 1.4 -> 5.0 時代のまとめ
  66. OSとCPU

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

  68. None
  69. 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
  70. 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)
  71. None
  72. None
  73. None
  74. AjaxとGoogle Maps

  75. None
  76. Google Maps以前

  77. AjaxとGoogle Maps

  78. Event LoopとAjax

  79. None
  80. event loop

  81. 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
  82. 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
  83. 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
  84. 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
  85. 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 コール
  86. 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
  87. 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
  88. 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
  89. 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
  90. 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 コールバック タスクキュー
  91. タスクキューも含めたアニメーション

  92. ajax コール

  93. ajax コールバック

  94. None
  95. None
  96. None
  97. • スレッドを意識せずにコールバックのみで非同期処理 • Event Loop • 非同期処理が庶民の手に! AjaxとGoogle Mapsのまとめ

  98. C10k problem

  99. 引用元: https://news.netcraft.com/archives/2019/02/28/february-2019-web-server-survey.html

  100. 引用元: https://news.netcraft.com/archives/2019/02/28/february-2019-web-server-survey.html

  101. None
  102. None
  103. 同時に走るスレッドは 高々CPUコア数

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

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

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

  107. None
  108. The Node.js Event Loop, Timers, and process.nextTick() https://nodejs.org/uk/docs/guides/event-loop-time rs-and-nexttick/#event-loop-explained

  109. None
  110. None
  111. ajax コール

  112. タイマーが指定時間に達していない2タスク

  113. None
  114. None
  115. ajax コールバック

  116. タイマー更新

  117. タイマー更新

  118. None
  119. None
  120. None
  121. None
  122. None
  123. None
  124. c10k problemまとめ • OS thread生成やOS threadのコンテキストスイッチのコスト • Event Loop、Event駆動モデル •

    コールバック重要
  125. JavaScript promise, async/await

  126. http://callbackhell.com/

  127. Promiseコード例 JavaScript Promiseの本 http://azu.github.io/promises-book/#pro mise-chain

  128. async/await コード例 JavaScript Promiseの本 http://azu.github.io/promises-book/#pro mise-chain

  129. Scala Futureとの類似性 Scala docs FUTURES AND PROMISES https://docs.scala-lang.org/overviews/co re/futures.html

  130. None
  131. JavaScript promise, async/await まとめ • Callback = 細分化された非同期処理 • 非同期処理のChaining

    ◦ ReactiveXなどのストリーム処理にも通じる • 「書きやすさ」という進化の方向性
  132. 関数型プログラミングと immutable object

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

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

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

    private • ...
  138. None
  139. Akkaとactor model

  140. rich, realtime -> 状態 ?

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

  142. IDでクエリ

  143. IDでクエリ

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

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

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

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

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

  149. None
  150. クエリはできたしかし...

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

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

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

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

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

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

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

  158. オブジェクトの内部状態

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

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

  161. Akka actorコードサンプル actor ! message class MyActor extends Actor {

    var state = ... def receive = { case MessageTypeX => ... case MessageTypeY => ... case MessageTypeZ => ... } }
  162. SenderはReceiverのスレッドセーフなキューに メッセージを送る

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

  165. thread-safe collections java.util.concurrent ConcurrentHashMap ConcurrentLinkedQueue ... CASを利用 Akka actorのメッセージキューは デフォルトで

    ConcurrentLinkedQueue
  166. thread-safe collections java.util.concurrent ConcurrentHashMap ConcurrentLinkedQueue ... CASを利用 Akka actorのメッセージキューは デフォルトで

    ConcurrentLinkedQueue
  167. Receiver側の動作を追っていく

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

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

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

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

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

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

    によって実行
  175. None
  176. volatile “write to a volatile variable establishes a happens-before relationship

    with subsequent reads of that same variable”
  177. > さらにvolatileな変数をread するとき、read側のスレッドは 最新のvolatile変数の変更のみ ならず、そこへ至るまでのコー ドの副作用まで観測することに なる

  178. Akka actor modelまとめ • shared mutableは難しいが重要な場合がある • actor modelはshared mutable管理の一つの解

    • AkkaはJava 5.0時代からのツールを内部で使う
  179. 関数型方面の進化 (Scala)

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

  181. 共通なパターン

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

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

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

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

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

  187. None
  188. None
  189. 非同期処理進化の方向性 • 処理の細分化・書きやすさ • 抽象化 • 堅牢性 • 効率

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

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

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

  193. 文献 Our World in Data https://ourworldindata.org/internet 世界のインターネットユーザ数の統計。 Statista https://www.statista.com/statistics/... 年間スマートフォン出荷台数の統計。

    https://twitter.com/csgillespie/status/… CPUクロック周波数に関するグラフ付きツイート。
  194. Oracle Concurrency guide https://docs.oracle.com/javase/tutorial/… Java 5.0やそれ以前から続く非同期処理技術に詳しい。 Computer Hope processor history

    https://www.computerhope.com/history/processor.htm AMDが2005年に初のdual-coreを発売など。 Java Memory ModelとJava 5.0 Oracle Concurrency in Swing guide https://docs.oracle.com/javase/tutorial/uiswing/... UIでのスレッド管理プラクティスとして一部今も通用する。
  195. 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を始め様々な概 念やコンパイラ最適化の影響などが解説されている。
  196. 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を題材に動画で解説 している。
  197. AjaxとGoogle Maps YouTube: Screen record of Google Maps in 2005

    https://youtu.be/PDG6tELjCOE 一般ユーザによる録画と思われる。 YouTube: What the heck is the event loop anyway? JSConf https://youtu.be/8aGhZQkoFbQ アニメーションを駆使したevent loop解説。100万再生以上。
  198. C10k problem ゆううきブログ: 2015年Webサーバアーキテクチャ序論 https://youtu.be/PDG6tELjCOE 現さくらインターネット研究所の坪内佑樹さんのブログ。C10k 問題や当時のサーバアーキテクチャを画像とともに解説。 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で書かれている。
  199. Inside NGINX: How We Designed for Performance & Scale https://www.nginx.com/blog/...

    nginx公式のアーキテクチャ解説。 MDN web docs: Concurrency model and Event Loop https://developer.mozilla.org/en-US/docs/... MozillaによるEvent Loop解説 JavaScript Promiseの本 https://azu.github.io/promises-book/ JavaScriptを中心に著名なエンジニアであるazu氏が書いた Promiseおよびasync/awaitを解説したウェブ上の本 JavaScript promise, async/await
  200. Akka docs: https://akka.io/docs/ 公式のドキュメント edX: Programming Reactive Systems https://www.edx.org/... AkkaのメンテナであったKonrad

    Malawski氏が中心となって 作ったオンライン学習コース Scala: Futures and Promises https://docs.scala-lang.org/overviews/core/futures.html Scala公式のFutureのドキュメント。Chainingの参考になる。 Akkaとactor model
  201. 関数型方面の進化(Scala) Monix https://monix.io/ イベント駆動で高パフォーマンスな非同期プログラムを書くサ ポートをするライブラリ。 Cats Effect https://typelevel.org/cats-effect/ I/Oを表す型を提供するライブラリ。同期および非同期の Effectを表現することができる。

    ZIO https://zio.dev/ 型安全でcomposableで非同期な処理をかけるライブラリ。
  202. YouTube: The Making of an IO - Daniel Spiewak https://youtu.be/g_jP47HFpWA

    関数型プログラムと非同期処理の関係を説明。Cats Effectの思想 やスレッドプール使い分けベストプラクティスにも触れる