Node.js イベント ループの内部: 詳細
Node.js シングルスレッド モデルの探索
Node.js はイベント駆動型の非同期 I/O アプローチを採用し、シングルスレッドで同時実行性の高い JavaScript ランタイム環境を実現します。シングルスレッドは一度に 1 つのことしか実行できないことを意味します。Node.js はどのようにしてたった 1 つのスレッドで高い同時実行性と非同期 I/O を実現するのでしょうか?この記事では、この質問を中心に Node.js のシングルスレッド モデルについて説明します。
高同時実行戦略
一般に、高い同時実行性を実現する解決策は、マルチスレッド モデルを提供することです。サーバーは各クライアント要求に 1 つのスレッドを割り当て、同期 I/O を使用します。システムは、スレッド切り替えを通じて同期 I/O 呼び出しの時間コストを補います。たとえば、Apache はこの戦略を使用します。 I/O 操作には通常時間がかかるため、このアプローチで高いパフォーマンスを達成するのは困難です。ただし、非常にシンプルなので、複雑な対話ロジックを実装できます。
実際、ほとんどの Web サーバー側はあまり計算を実行しません。リクエストを受信した後、そのリクエストを他のサービス (データベースの読み取りなど) に渡し、結果が返されるのを待ち、最後に結果をクライアントに送信します。したがって、Node.js はシングルスレッド モデルを使用してこの状況に対処します。受信リクエストごとにスレッドを割り当てる代わりに、メイン スレッドを使用してすべてのリクエストを処理し、I/O 操作を非同期で処理することで、スレッドの作成、破棄、およびスレッド間の切り替えに伴うオーバーヘッドと複雑さを回避します。
イベントループ
Node.js はメインスレッドでイベント キューを維持します。リクエストを受信すると、そのリクエストはイベントとしてこのキューに追加され、その後も引き続き他のリクエストを受信します。メインスレッドがアイドル状態 (リクエストが受信されていない状態) になると、イベント キューのループを開始して、処理するイベントがあるかどうかを確認します。 2 つのケースがあります。非 I/O タスクの場合、メインスレッドはそれらを直接処理し、コールバック関数を介して上位層に戻ります。 I/O タスクの場合、スレッド プールからスレッドを取得してイベントを処理し、コールバック関数を指定して、キュー内の他のイベントをループし続けます。
スレッド内の I/O タスクが完了すると、指定されたコールバック関数が実行され、完了したイベントがイベント キューの最後に配置され、イベント ループを待ちます。メインスレッドがこのイベントを再びループすると、それを直接処理して上位層に返します。このプロセスはイベント ループと呼ばれ、その動作原理は次の図に示されています。
この図は、Node.js の全体的な動作原理を示しています。 Node.js は、左から右、上から下の順に、アプリケーション層、V8 エンジン層、Node API 層、LIBUV 層の 4 つの層に分かれています。
- アプリケーション層: JavaScript インタラクション層です。一般的な例は、http や fs などの Node.js モジュールです。
- V8 エンジン層: V8 エンジンを使用して JavaScript 構文を解析し、下位層 API と対話します。
- ノード API 層: 通常は C で実装される上位層モジュールのシステム コールを提供し、オペレーティング システムと対話します。
- LIBUV レイヤー: イベント ループ、ファイル操作などを実現するクロスプラットフォームの基礎となるカプセル化であり、非同期を実現するための Node.js の中核です。
Linux プラットフォームでも Windows プラットフォームでも、Node.js は内部でスレッド プールを使用して非同期 I/O 操作を完了し、LIBUV は異なるプラットフォームの呼び出しを統合します。したがって、Node.js のシングル スレッドは、JavaScript がシングル スレッドで実行されることを意味するだけであり、Node.js 全体がシングル スレッドであることを意味するわけではありません。
動作原理
非同期を実現する Node.js の中核はイベントにあります。つまり、すべてのタスクをイベントとして扱い、イベント ループを通じて非同期効果をシミュレートします。この事実をより具体的かつ明確に理解して受け入れるために、疑似コードを使用してその動作原理を以下に説明します。
1. イベントキューを定義する
これはキューなので、先入れ先出し (FIFO) データ構造です。 JS 配列を使用して次のように記述します。
/** * Define the event queue * Enqueue: push() * Dequeue: shift() * Empty queue: length === 0 */ let globalEventQueue = [];
配列を使用してキュー構造をシミュレートします。配列の最初の要素はキューの先頭で、最後の要素はキューの末尾です。 Push() はキューの最後に要素を挿入し、shift() はキューの先頭から要素を削除します。このようにして、単純なイベントキューが実現されます。
2. リクエスト受付口の定義
以下に示すように、すべてのリクエストがインターセプトされ、処理関数に入ります。
/** * Receive user requests * Every request will enter this function * Pass parameters request and response */ function processHttpRequest(request, response) { // Define an event object let event = createEvent({ params: request.params, // Pass request parameters result: null, // Store request results callback: function() {} // Specify a callback function }); // Add the event to the end of the queue globalEventQueue.push(event); }
この関数は、ユーザーのリクエストをイベントとしてパッケージ化してキューに入れ、他のリクエストを引き続き受信します。
3. イベントループを定義する
メインスレッドがアイドル状態になると、イベントキューのループが開始されます。したがって、イベント キューをループする関数を定義する必要があります。
/** * The main body of the event loop, executed by the main thread when appropriate * Loop through the event queue * Handle non-IO tasks * Handle IO tasks * Execute callbacks and return to the upper layer */ function eventLoop() { // If the queue is not empty, continue to loop while (this.globalEventQueue.length > 0) { // Take an event from the head of the queue let event = this.globalEventQueue.shift(); // If it's a time-consuming task if (isIOTask(event)) { // Take a thread from the thread pool let thread = getThreadFromThreadPool(); // Hand it over to the thread to handle thread.handleIOTask(event); } else { // After handling non-time-consuming tasks, directly return the result let result = handleEvent(event); // Finally, return to V8 through the callback function, and then V8 returns to the application event.callback.call(null, result); } } }
メインスレッドはイベントキューを継続的に監視します。 I/O タスクの場合はスレッド プールに渡して処理し、非 I/O タスクの場合は自身で処理して戻ります。
4. I/O タスクの処理
スレッド プールはタスクを受信した後、データベースの読み取りなどの I/O 操作を直接処理します。
/** * Define the event queue * Enqueue: push() * Dequeue: shift() * Empty queue: length === 0 */ let globalEventQueue = [];
I/O タスクが完了すると、コールバックが実行され、リクエスト結果がイベントに格納され、イベントがキューに戻されてループを待ちます。最後に、現在のスレッドが解放されます。メインスレッドがこのイベントを再度ループすると、直接処理されます。
上記のプロセスを要約すると、Node.js はリクエストの受信にメイン スレッドを 1 つだけ使用していることがわかります。リクエストを受信した後、それらを直接処理せずにイベント キューに入れ、引き続き他のリクエストを受信します。アイドル状態の場合、イベント ループを通じてこれらのイベントを処理し、非同期効果を実現します。もちろん、I/O タスクの場合は、システム レベルでスレッド プールに依存して処理する必要があります。
したがって、Node.js 自体はマルチスレッド プラットフォームですが、単一のスレッドで JavaScript レベルのタスクを処理するということが簡単に理解できます。
CPU を集中的に使用するタスクが欠点である
ここまでで、Node.js のシングルスレッド モデルについて簡単かつ明確に理解できたはずです。イベント駆動型モデルにより、高い同時実行性と非同期 I/O を実現します。ただし、Node.js が苦手な点もあります。
上で述べたように、I/O タスクの場合、Node.js はそれらをスレッド プールに渡して非同期処理を行います。これは効率的かつシンプルです。したがって、Node.js は I/O 集中型のタスクを処理するのに適しています。ただし、すべてのタスクが I/O 集中型であるわけではありません。 CPU を大量に使用するタスク、つまり、データの暗号化と復号化 (node.bcrypt.js)、データの圧縮と解凍 (node-tar) などの CPU 計算のみに依存する操作が発生した場合、Node.js はそれらを 1 つずつ処理します。 1つ。前のタスクが完了していない場合、後続のタスクは待つことしかできません。以下の図に示すように:
イベントキューでは、前の CPU 計算タスクが完了していないと、後続のタスクがブロックされ、応答が遅くなります。オペレーティング システムがシングルコアの場合は、許容できる可能性があります。しかし、現在、ほとんどのサーバーはマルチ CPU またはマルチコアであり、Node.js には EventLoop が 1 つしかありません。つまり、占有する CPU コアは 1 つだけです。 Node.js が CPU を集中的に使用するタスクによって占有され、他のタスクがブロックされると、CPU コアがアイドル状態のままになり、リソースが無駄になります。
したがって、Node.js は CPU を集中的に使用するタスクには適していません。
アプリケーションシナリオ
- RESTful API: リクエストとレスポンスには少量のテキストのみが必要で、多くの論理処理は必要ありません。したがって、数万の接続を同時に処理できます。
- チャット サービス: 軽量でトラフィック量が多く、複雑な計算ロジックはありません。
Leapcell: Web ホスティング、非同期タスク、Redis のための次世代サーバーレス プラットフォーム
最後に、Node.js サービスのデプロイに最適なプラットフォームである Leapcell を紹介します。
1. 多言語サポート
- JavaScript、Python、Go、または Rust で開発します。
2. 無制限のプロジェクトを無料でデプロイ
- 使用料金のみお支払いください。リクエストや料金はかかりません。
3. 比類のないコスト効率
- アイドル料金なしの従量課金制です。
- 例: $25 は、平均応答時間 60 ミリ秒で 694 万のリクエストをサポートします。
4. 合理化された開発者エクスペリエンス
- 直感的な UI でセットアップが簡単です。
- 完全に自動化された CI/CD パイプラインと GitOps の統合。
- 実用的な洞察を得るリアルタイムのメトリクスとログ。
5. 容易な拡張性と高性能
- 自動スケーリングにより、高い同時実行性を簡単に処理できます。
- 運用上のオーバーヘッドがゼロ - 構築だけに集中できます。
ドキュメントでさらに詳しく見てみましょう!
Leapcell Twitter: https://x.com/LeapcellHQ
以上がNode.js イベント ループの内部: 詳細の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。
