ノードJS内部
あなたがレストランに行って、「私は同時に何百人もの料理を作ることができます、そしてあなた方の誰もお腹を空かせることはありません」と約束する一人のシェフがいると仮定します。不可能に聞こえますよね?この 1 つのチェックを、複数の注文をすべて管理し、すべての顧客に料理を提供する Node JS と考えることができます。
誰かに「Node JS とは何ですか?」という質問をすると、必ず「Node JS はブラウザ環境の外で JavaScript を実行するために使用されるランタイムです」という答えが返ってきます。
しかし、ランタイムとは何を意味するのでしょうか?... ランタイム環境は、コードの実行が特定のプログラミング言語で記述されるソフトウェア インフラストラクチャです。コードの実行、エラーの処理、メモリの管理を行うためのすべてのツール、ライブラリ、機能が備わっており、基盤となるオペレーティング システムやハードウェアと対話できます。
Node JS にはこれらがすべて含まれています。
コードを実行するには Google V8 エンジン。
fs、crypto、http などのコア ライブラリと API。
非同期およびノンブロッキング I/O 操作をサポートする Libuv やイベント ループなどのインフラストラクチャ。
これで、Node JS がランタイムと呼ばれる理由がわかりました。
このランタイムは、V8 と libuv という 2 つの独立した依存関係で構成されます。
V8 は Google Chrome でも使用されているエンジンで、Google が開発・管理しています。 Node JS では JavaScript コードを実行します。コマンド node Index.js を実行すると、Node JS はこのコードを V8 エンジンに渡します。 V8 はこのコードを処理して実行し、結果を提供します。たとえば、コードが「Hello, World!」をログに記録するとします。コンソールに対して、V8 はこれを実現する実際の実行を処理します。
libuv ライブラリには、ネットワーク、I/O 操作、または時間関連の操作などの機能が必要な場合にオペレーティング システムへのアクセスを可能にする C コードが含まれています。これは、Node JS とオペレーティング システムの間のブリッジとして機能します。
libuv は次の操作を処理します:
ファイル システム操作: ファイルの読み取りまたは書き込み (fs.readFile、fs.writeFile)。
ネットワーク: HTTP リクエスト、ソケットの処理、またはサーバーへの接続。
タイマー: setTimeout や setInterval などの関数を管理します。
ファイル読み取りなどのタスクは Libuv スレッド プールによって処理され、タイマーは Libuv のタイマー システムによって処理され、ネットワーク呼び出しは OS レベルの API によって処理されます。
Node JS はシングルスレッドですか?
次の例を見てください。
const fs = require('fs'); const path = require('path'); const filePath = path.join(__dirname, 'file.txt'); const readFileWithTiming = (index) => { const start = Date.now(); fs.readFile(filePath, 'utf8', (err, data) => { if (err) { console.error(`Error reading the file for task ${index}:`, err); return; } const end = Date.now(); console.log(`Task ${index} completed in ${end - start}ms`); }); }; const startOverall = Date.now(); for (let i = 1; i <= 4; i++) { readFileWithTiming(i); } process.on('exit', () => { const endOverall = Date.now(); console.log(`Total execution time: ${endOverall - startOverall}ms`); });
同じファイルを 4 回読み取り、それらのファイルを読み取る時間を記録しています。
このコードから次の出力が得られます。
Task 1 completed in 50ms Task 2 completed in 51ms Task 3 completed in 52ms Task 4 completed in 53ms Total execution time: 54ms
ほぼ 50 ミリ秒で 4 つのファイルすべての読み取りが完了したことがわかります。 Node JS がシングルスレッドの場合、これらすべてのファイルの読み取り操作はどのようにして同時に完了するのでしょうか?
この質問は、libuv ライブラリがスレッド プールを使用していると答えています。スレッド プールはスレッドの束です。デフォルトでは、スレッド プール サイズは 4 で、libuv によって一度に 4 つのリクエストを処理できることを意味します。
1 つのファイルを 4 回読み取る代わりに、このファイルを 6 回読み取る別のシナリオを考えてみましょう。
const fs = require('fs'); const path = require('path'); const filePath = path.join(__dirname, 'file.txt'); const readFileWithTiming = (index) => { const start = Date.now(); fs.readFile(filePath, 'utf8', (err, data) => { if (err) { console.error(`Error reading the file for task ${index}:`, err); return; } const end = Date.now(); console.log(`Task ${index} completed in ${end - start}ms`); }); }; const startOverall = Date.now(); for (let i = 1; i <= 4; i++) { readFileWithTiming(i); } process.on('exit', () => { const endOverall = Date.now(); console.log(`Total execution time: ${endOverall - startOverall}ms`); });
出力は次のようになります:
Task 1 completed in 50ms Task 2 completed in 51ms Task 3 completed in 52ms Task 4 completed in 53ms Total execution time: 54ms
読み取り操作 1 と 2 が完了し、スレッド 1 と 2 が解放されたとします。
最初の 4 回はファイルの読み取りにほぼ同じ時間がかかりますが、このファイルを 5 回目と 6 回目に読み取ると、読み取り操作を完了するまでに最初の 4 回の読み取り操作に比べてほぼ 2 倍の時間がかかることがわかります。 。
これは、スレッド プール サイズがデフォルトで 4 であるため、4 つの読み取り操作が同時に処理されますが、ファイルの読み取りが 2 回 (5 回目と 6 回目) 行われるため、すべてのスレッドが何らかの作業を行っているため、libuv が待機するために発生します。 4 つのスレッドのうち 1 つが実行を完了すると、5 回目の読み取り操作がそのスレッドに対して処理され、6 回目の読み取り操作も同様に実行されます。それがより時間がかかる理由です。
つまり、Node JS はシングルスレッドではありません。
しかし、なぜ一部の人はそれをシングルスレッドと呼ぶのでしょうか?
これは、メイン イベント ループがシングルスレッドであるためです。このスレッドは、非同期コールバックの処理やタスクの調整など、Node JS コードの実行を担当します。ファイル I/O などのブロック操作は直接処理しません。
コード実行の流れはこんな感じです。
- 同期コード (V8):
Node.js は、V8 JavaScript エンジンを使用して、すべての同期 (ブロッキング) コードを 1 行ずつ実行します。
- 委任された非同期タスク:
fs.readFile、setTimeout、http リクエストなどの非同期操作は、Libuv ライブラリまたは他のサブシステム (OS など) に送信されます。
- タスクの実行:
ファイル読み取りなどのタスクは Libuv スレッド プールによって処理され、タイマーは Libuv のタイマー システムによって処理され、ネットワーク呼び出しは OS レベルの API によって処理されます。
- キューに入れられたコールバック:
非同期タスクが完了すると、それに関連付けられたコールバックがイベント ループのキューに送信されます。
- イベント ループはコールバックを実行します:
イベント ループはキューからコールバックを取得して 1 つずつ実行し、ノンブロッキングな実行を保証します。
スレッド プールのサイズは、process.env.UV_THREADPOOL_SIZE = 8 を使用して変更できます。
今、スレッド数を高く設定すれば、大量のリクエストにも対応できるのではないかと考えています。皆さんも私と同じように考えていただければ幸いです。
しかし、それは私たちが考えていたこととは逆です。
スレッド数を特定の制限を超えて増やすと、コードの実行が遅くなります。
次の例を見てください。
const fs = require('fs'); const path = require('path'); const filePath = path.join(__dirname, 'file.txt'); const readFileWithTiming = (index) => { const start = Date.now(); fs.readFile(filePath, 'utf8', (err, data) => { if (err) { console.error(`Error reading the file for task ${index}:`, err); return; } const end = Date.now(); console.log(`Task ${index} completed in ${end - start}ms`); }); }; const startOverall = Date.now(); for (let i = 1; i <= 4; i++) { readFileWithTiming(i); } process.on('exit', () => { const endOverall = Date.now(); console.log(`Total execution time: ${endOverall - startOverall}ms`); });
出力:
高スレッド プール サイズ (100 スレッド)
Task 1 completed in 50ms Task 2 completed in 51ms Task 3 completed in 52ms Task 4 completed in 53ms Total execution time: 54ms
次に、スレッド プール サイズを 4 (デフォルト サイズ) に設定した場合の出力を示します。
デフォルトのスレッド プール サイズ (4 スレッド)
const fs = require('fs'); const path = require('path'); const filePath = path.join(__dirname, 'file.txt'); const readFileWithTiming = (index) => { const start = Date.now(); fs.readFile(filePath, 'utf8', (err, data) => { if (err) { console.error(`Error reading the file for task ${index}:`, err); return; } const end = Date.now(); console.log(`Task ${index} completed in ${end - start}ms`); }); }; const startOverall = Date.now(); for (let i = 1; i <= 6; i++) { readFileWithTiming(i); } process.on('exit', () => { const endOverall = Date.now(); console.log(`Total execution time: ${endOverall - startOverall}ms`); });
合計実行時間には 100ms の差があることがわかります。合計実行時間 (スレッド プール サイズ 4) は 600 ミリ秒、合計実行時間 (スレッド プール サイズ 100) は 700 ミリ秒です。したがって、スレッド プール サイズが 4 の場合、所要時間は短くなります。
スレッドの数が多い != より多くのタスクを同時に処理できるのはなぜですか?
最初の理由は、各スレッドに独自のスタックとリソース要件があることです。スレッドの数を増やすと、最終的にはメモリ不足または CPU リソースの状態が発生します。
2 番目の理由は、オペレーティング システムがスレッドをスケジュールする必要があることです。スレッドが多すぎると、OS はスレッド間の切り替え (コンテキスト切り替え) に多くの時間を費やし、オーバーヘッドが追加され、パフォーマンスが向上するどころかパフォーマンスが低下します。
スケーラビリティと高いパフォーマンスを実現するためにスレッド プール サイズを増やすことではなく、クラスタリングなどの適切なアーキテクチャを使用し、タスクの性質 (I/O 対 CPU バウンド) を理解することが重要であると言えます。 ) と Node.js のイベント駆動モデルがどのように機能するか。
お読みいただきありがとうございます。
以上がノード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)

ホットトピック











フロントエンドのサーマルペーパーチケット印刷のためのよくある質問とソリューションフロントエンド開発におけるチケット印刷は、一般的な要件です。しかし、多くの開発者が実装しています...

JavaScriptは現代のWeb開発の基礎であり、その主な機能には、イベント駆動型のプログラミング、動的コンテンツ生成、非同期プログラミングが含まれます。 1)イベント駆動型プログラミングにより、Webページはユーザー操作に応じて動的に変更できます。 2)動的コンテンツ生成により、条件に応じてページコンテンツを調整できます。 3)非同期プログラミングにより、ユーザーインターフェイスがブロックされないようにします。 JavaScriptは、Webインタラクション、シングルページアプリケーション、サーバー側の開発で広く使用されており、ユーザーエクスペリエンスとクロスプラットフォーム開発の柔軟性を大幅に改善しています。

スキルや業界のニーズに応じて、PythonおよびJavaScript開発者には絶対的な給与はありません。 1. Pythonは、データサイエンスと機械学習でさらに支払われる場合があります。 2。JavaScriptは、フロントエンドとフルスタックの開発に大きな需要があり、その給与もかなりです。 3。影響要因には、経験、地理的位置、会社の規模、特定のスキルが含まれます。

この記事の視差スクロールと要素のアニメーション効果の実現に関する議論では、Shiseidoの公式ウェブサイト(https://www.shisido.co.co.jp/sb/wonderland/)と同様の達成方法について説明します。

JavaScriptを学ぶことは難しくありませんが、挑戦的です。 1)変数、データ型、関数などの基本概念を理解します。2)非同期プログラミングをマスターし、イベントループを通じて実装します。 3)DOM操作を使用し、非同期リクエストを処理することを約束します。 4)一般的な間違いを避け、デバッグテクニックを使用します。 5)パフォーマンスを最適化し、ベストプラクティスに従ってください。

JavaScriptの最新トレンドには、TypeScriptの台頭、最新のフレームワークとライブラリの人気、WebAssemblyの適用が含まれます。将来の見通しは、より強力なタイプシステム、サーバー側のJavaScriptの開発、人工知能と機械学習の拡大、およびIoTおよびEDGEコンピューティングの可能性をカバーしています。

同じIDを持つ配列要素をJavaScriptの1つのオブジェクトにマージする方法は?データを処理するとき、私たちはしばしば同じIDを持つ必要性に遭遇します...

フロントエンドのVSCodeと同様に、パネルドラッグアンドドロップ調整機能の実装を調べます。フロントエンド開発では、VSCODEと同様のVSCODEを実装する方法...
