$30 off During Our Annual Pro Sale. View Details »

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

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

リチャード 伊真岡

August 30, 2019
Tweet

More Decks by リチャード 伊真岡

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  6. JavaScript: promise, async/await
    Go: goroutine, channel
    Kotlin: Coroutine
    Java: java.util.concurrent (1.5, 8.0)
    Scala: Future
    ReactiveX
    チュートリアルを見れば
    それっぽい物は書ける...

    View Slide

  7. 「スレッドセーフじゃなくない?」
    そんなときコードレビューで...!!
    非同期処理にしたはずが画面フリーズ!
    エラーが出たけど原因をたどれない...
    さらにランタイム(本番環境)で...

    View Slide

  8. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  16. View Slide

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

    View Slide

  18. View Slide

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

    View Slide

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

    View Slide

  21. View Slide

  22. View Slide

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

    View Slide

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

    View Slide

  25. View Slide

  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

    View Slide

  27. View Slide

  28. View Slide

  29. View Slide

  30. java.util.concurrent
    (Java 5.0 以降)

    View Slide

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

    View Slide

  32. View Slide

  33. View Slide

  34. View Slide

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

    View Slide

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

    View Slide

  37. View Slide

  38. View Slide

  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を上書き)

    View Slide

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

    View Slide

  41. View Slide

  42. View Slide

  43. View Slide

  44. synchronized
    atomic
    happens-before

    View Slide

  45. happens-before

    View Slide

  46. View Slide

  47. View Slide

  48. View Slide

  49. data race
    (memory-consistency error)

    View Slide

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

    View Slide

  51. View Slide

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

    View Slide

  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/

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  58.  1.CAS成功例

    View Slide

  59.  2.CAS成功例

    View Slide

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

    View Slide

  61.  1.CAS失敗例

    View Slide

  62.  2.CAS失敗例

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  66. OSとCPU

    View Slide

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

    View Slide

  68. View Slide

  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

    View Slide

  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)

    View Slide

  71. View Slide

  72. View Slide

  73. View Slide

  74. AjaxとGoogle Maps

    View Slide

  75. View Slide

  76. Google Maps以前

    View Slide

  77. AjaxとGoogle Maps

    View Slide

  78. Event LoopとAjax

    View Slide

  79. View Slide

  80. event loop

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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 コール

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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 コールバック
    タスクキュー

    View Slide

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

    View Slide

  92. ajax コール

    View Slide

  93. ajax コールバック

    View Slide

  94. View Slide

  95. View Slide

  96. View Slide

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

    View Slide

  98. C10k problem

    View Slide

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

    View Slide

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

    View Slide

  101. View Slide

  102. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  107. View Slide

  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

    View Slide

  109. View Slide

  110. View Slide

  111. ajax コール

    View Slide

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

    View Slide

  113. View Slide

  114. View Slide

  115. ajax コールバック

    View Slide

  116. タイマー更新

    View Slide

  117. タイマー更新

    View Slide

  118. View Slide

  119. View Slide

  120. View Slide

  121. View Slide

  122. View Slide

  123. View Slide

  124. c10k problemまとめ
    ● OS thread生成やOS threadのコンテキストスイッチのコスト
    ● Event Loop、Event駆動モデル
    ● コールバック重要

    View Slide

  125. JavaScript promise, async/await

    View Slide

  126. http://callbackhell.com/

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  130. View Slide

  131. JavaScript promise, async/await
    まとめ
    ● Callback = 細分化された非同期処理
    ● 非同期処理のChaining
    ○ ReactiveXなどのストリーム処理にも通じる
    ● 「書きやすさ」という進化の方向性

    View Slide

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

    View Slide

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

    View Slide

  134. View Slide

  135. View Slide

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

    View Slide

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

    View Slide

  138. View Slide

  139. Akkaとactor model

    View Slide

  140. rich, realtime -> 状態 ?

    View Slide

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

    View Slide

  142. IDでクエリ

    View Slide

  143. IDでクエリ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  149. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  163. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  168. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  175. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  179. 関数型方面の進化
    (Scala)

    View Slide

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

    View Slide

  181. 共通なパターン

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  187. View Slide

  188. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  193. 文献
    Our World in Data https://ourworldindata.org/internet
    世界のインターネットユーザ数の統計。
    Statista https://www.statista.com/statistics/...
    年間スマートフォン出荷台数の統計。
    https://twitter.com/csgillespie/status/…
    CPUクロック周波数に関するグラフ付きツイート。

    View Slide

  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でのスレッド管理プラクティスとして一部今も通用する。

    View Slide

  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を始め様々な概
    念やコンパイラ最適化の影響などが解説されている。

    View Slide

  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を題材に動画で解説
    している。

    View Slide

  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万再生以上。

    View Slide

  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で書かれている。

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide