Slide 1

Slide 1 text

Node.jsデザインパターン を読んで 2022 / 6 / 23

Slide 2

Slide 2 text

ゴール - libuvとはなんなのか? - Reactor Patternとはなんなのか? - イベントループとはなんなのか? がなんとなく理解できるようになること

Slide 3

Slide 3 text

Node js 公式より Node.js はスケーラブルなネットワークアプリケーションを構築するために設計された非同期 型のイベント駆動の JavaScript 環境です。 特徴としては - シングルスレッド - ノンブロッキング I / O + イベントループ(libuv) = 非同期 I / O が挙げられます

Slide 4

Slide 4 text

シングルスレッドとは - CPUの処理単位のことでCPUの利用単位としてはプロセスとスレッドがあり、プロ セスが一つ以上のスレッドをもつ - シングルスレッドは文字通りスレッド一つでプログラムを処理すること

Slide 5

Slide 5 text

補足 マルチスレッド マルチスレッドでは以下のように処理を複数のスレッドに分散させることができる。 シングルスレッドでは処理をスレッドに分散するのではなく時間軸で分散する

Slide 6

Slide 6 text

ノンブロッキングI / O ノンブロッキングI / O - I / O処理が走った時にI / O処理ができない場合は即座にエラーを返しブロックさせ ない方式 - データが処理可能になるまでリクエストを送る必要がある 非同期I / O - I / O処理が走った時に処理が完了するまでバックグラウンドで待機しI / O処理が 完了したタイミングで通知を返すことによってブロックしない方式

Slide 7

Slide 7 text

Busy Wait - ノンブロッキングI / Oの処理方法の一つ - I / Oの処理が戻されるまでループを回してポーリングする方法のこと - この方法ではI / O処理可能になるまでループするためCPUを食うことになる

Slide 8

Slide 8 text

Reactor Pattern I / Oに基づいた処理はI / O完了の通知を受け取ってからデータを取り出し行う必要が ある シングルスレッドで複数の処理を行うために - ノンブロッキングI / O - イベント多重分離(Event demultiplexing) - イベントループ がある dataを読み取ってinputに 代入する前にconsole.log に到達するので 何も出力されない

Slide 9

Slide 9 text

イベント多重分離(event demultiplexing) 一つにまとまった処理を複数に分離することをデマルチプレキシング(多重分離)という この機能はOSに提供されており、I / Oの完了が完了した時に〇〇するができるように この方法を使用することによって時間軸で処理を分散させシングルスレッドでも並行に 処理を実行することができる

Slide 10

Slide 10 text

libuv デマルチプレクサの実装はOSごとに異なっている(Linuxのepoll, macOSのkqueueな ど) OS差分を抽象化し吸収するために、Nodeのコア開発チームはlibuvというCのライブラ リを作成している。 libuvがこのあと出てくるイベントループや非同期処理をNode.jsに提供している

Slide 11

Slide 11 text

Reactor PatternでのI / Oリクエスト時の実際の動き - 基本的にはI / Oタスクのそれぞれにハンドラ( Node.jsではコールバック)を対応させる - イベントループにおいて新イベントが生成・処理されるたびにハンドラが呼び出される

Slide 12

Slide 12 text

1 アプリがデマルチプレクサに対して I / O要 求を発行する その際にハンドラが指定され、 I / O要求の 発行はノンブロッキングな関数呼び出しな ので即座にアプリケーションに処理が戻る

Slide 13

Slide 13 text

2 I / O要求が届くとデマルチプレクサが キューに入れる

Slide 14

Slide 14 text

3, 4 - イベントループにおいて、キューの 中の全てのイベントが操作されて処 理される - 各イベントに対して、登録済みのハ ンドラが呼び出される

Slide 15

Slide 15 text

5a, 5b - ハンドラの呼び出しが完了するとイ ベントループで次のイベントが処理 される - ハンドラ内で更にI / O要求が発行さ れた場合はイベントループに処理を 戻す前に1の処理を繰り返す

Slide 16

Slide 16 text

6 イベントループで全てのイベントが処理さ れると新しいイベントが送られてくるまで待 機する

Slide 17

Slide 17 text

Event Queue libuvから提供されるキューとNode.jsが提供するキューがある libuv - Expired timers / intervals queue  - IO Events Queue  - Immediates Queue  - Close Handlers Queue Node.js - nextTick Queue - microTask Queue libuvが提供しているキューはイベントループの各フェーズに紐づいており、フェーズが実行され る毎にNode.jsが提供しているキューが実行される

Slide 18

Slide 18 text

Event loop イベントループには6つのフェーズがあり、 3・4・5aがこの6つの順番で行われる それぞれのフェーズは実行するコールバッ クのFIFOキューをもつ JavaScriptの実行はidle,prepare以外のど こかのフェーズで実行され キューが空になるかコールバックの上限に 達したらイベントは次のフェーズへ遷移す る

Slide 19

Slide 19 text

3, 4, 5a - イベントループにおいて、キューの 中の全てのイベントが操作されて処 理される - 各イベントに対して、登録済みのハ ンドラが呼び出される - ハンドラの呼び出しが完了するとイ ベントループで次のイベントが処理 される 再掲

Slide 20

Slide 20 text

イベントループとキューの対応表 libuvは各フェーズ毎に結果を JavaScriptに伝える この時にnextTickQueueとmicroTaskQueue に入れられた内容を処理する

Slide 21

Slide 21 text

nextTickQueue process.nextTickのコールバックが実行される 非同期処理の中で最初に実行される

Slide 22

Slide 22 text

microTaskQueue Promiseオブジェクトのコールバックが実行される

Slide 23

Slide 23 text

nextTickの方が先に実行される

Slide 24

Slide 24 text

補足 イベントループ

Slide 25

Slide 25 text

イベントループ

Slide 26

Slide 26 text

Event loop (Timer) setTimer, setIntervalなどのタイマー系APIの期限切れコールバックが実行される

Slide 27

Slide 27 text

Event loop (pending callback) I / O操作の成功、エラーのコールバック関数が実行される この場合だと console.log(err) か console.log(data)

Slide 28

Slide 28 text

Event loop (idle, prepare, poll) オプショナルなフェーズでpollフェーズが行われる場合はidle / prepareフェーズが行わ れる - I / O をブロックしてポーリングする時間を計算する - キュー内のイベントをキューが空になるかシステム固有の上限に達するまで処理す る

Slide 29

Slide 29 text

Event loop (check) - setImmediateのコールバック専用のフェーズ - setImmediateで登録された全てのコールバックを実行する

Slide 30

Slide 30 text

Event loop (close callback) 全てのcloseフェーズのコールバックが実行される

Slide 31

Slide 31 text

実際に

Slide 32

Slide 32 text

Node.jsのアーキテクチャ

Slide 33

Slide 33 text

まとめ - Node.jsはイベントループ + ノンブロッキング I / O、非同期 I / Oを使うことでI / O 待ちの時間を時間軸に分散している - イベントループ、I / O完了通知などの根幹の部分はOS差分を吸収するためにlibuv というライブラリを使用している

Slide 34

Slide 34 text

ご清聴ありがとうございました

Slide 35

Slide 35 text

参考資料 - https://www.oreilly.co.jp/books/9784873118734/ - https://blog.insiderattack.net/event-loop-and-the-big-picture-nodejs-event-loop-part-1-1cb67a182 810 - https://zenn.dev/estra/books/js-async-promise-chain-event-loop - https://blog.takanabe.tokyo/2015/03/%E3%83%8E%E3%83%B3%E3%83%96%E3%83%AD%E 3%83%83%E3%82%AD%E3%83%B3%E3%82%B0i/o%E3%81%A8%E9%9D%9E%E5%90%8 C%E6%9C%9Fi/o%E3%81%AE%E9%81%95%E3%81%84%E3%82%92%E7%90%86%E8%A 7%A3%E3%81%99%E3%82%8B/ - https://blog.hiroppy.me/entry/nodejs-event-loop - https://engineer.recruit-lifestyle.co.jp/techblog/2019-12-13-node-async-io/ - https://nodejs.org/en/about/ - https://libuv.org/