Node.jsが数千のリクエストを処理する方法

Node.jsはシングルスレッドだと言われます。

それなのに、停止することなく数千のリクエストを処理し、ファイルを読み込み、APIコールを行います。

どうやって実現しているのでしょうか?

その答えはlibuvです。

libuvはC言語のライブラリです。これにより、Node.jsは非同期かつノンブロッキングなI/O機能を持つことができます。JavaScript単体では、ファイルの読み込みやネットワークソケットの管理を行うことはできません。Node.jsはlibuvを使用してオペレーティングシステムと通信します。

libuvがなければ、ファイルを読み込むたびにJavaScriptは停止してしまいます。アプリケーションは応答不能になるでしょう。

libuvがあれば、ファイルの読み込みはバックグラウンドで行われます。JavaScriptは他のコードの実行を継続できます。

例:

console.log("Start");

fs.readFile("data.txt", "utf8", (err, data) => {
  console.log(data);
});

console.log("End");

出力: Start End (ファイルの内容)

Node.jsはファイルの読み込みが完了する前に「End」を出力します。待機はしません。

libuvがコードを管理する方法:

イベントループ (The Event Loop): libuvはタスクが完了したかどうかを確認するループを実行します。タスクが完了すると、コールバックをキューに追加します。 • スレッドプール (Thread Pool): JavaScriptは1つのスレッドを使用しますが、libuvはワーカー・スレッドのプールを使用します。デフォルトでは、このプールには4つのスレッドがあります。これらのスレッドは、以下のような重いタスクを処理します:

  • ファイルシステムの操作
  • DNSルックアップ
  • 圧縮
  • 暗号化 • ネットワーキング (Networking): libuvはHTTP、TCP、UDPソケットを管理します。これにより、サーバーは一度に多くの接続を処理できます。 • タイマー (Timers): libuvはsetTimeoutsetIntervalを処理します。

実行フローは次のようになります:

  1. JavaScriptがコードを実行します。
  2. libuvが重いタスクをバックグラウンドに送ります。
  3. JavaScriptは次の行の実行を続けます。
  4. タスクが完了すると、libuvがイベントループに通知します。
  5. イベントループがコールバックを実行します。

ピザ屋を例に考えてみましょう。

libuvがなければ、あなたはカウンターに立ち、「料理はできましたか?」と10秒ごとに聞き続けます。これでは列を止めてしまうことになります。

libuvがあれば、注文をして席に座り、通知を待ちます。ピザができるまで、他のことをして自由に過ごせます。

まとめ:

• JavaScriptの実行: V8 Engine • イベントループ: libuv • ファイルI/O: libuv • ネットワーク: libuv • タイマー: libuv

libuvはNode.jsの高速性を維持するエンジンです。

出典: https://dev.to/kavindotdev/understanding-libuv-the-engine-behind-nodejs-asynchronous-programming-3n7o