Node.js のイベント ループ: 非同期操作の管理

Barbara Streisand
リリース: 2024-10-18 22:44:03
オリジナル
897 人が閲覧しました

Node.js はノンブロッキング、非同期の性質で知られており、イベント ループがこの動作の中心にあります。これにより、メインスレッドがブロックされずに維持されるため、複数の操作が互いの終了を待たずに効率的に実行できるようになります。この記事では、イベント ループがどのように機能するかを調査し、その 6 つのフェーズに分けて、イベント ループのブロックを防ぐ戦略について説明します。

Node.js のイベント ループを理解する

Node.js のイベント ループにより非同期処理が可能になり、メイン スレッドのブロックが回避されます。 6 つのフェーズで動作します:

Event Loop in Node.js: Managing Asynchronous Operations

Node.js のイベント ループを理解する

イベント ループは、非同期操作の処理を担当するメカニズムです。 I/O やタイマーなどの操作が完了するたびに、イベント ループはその操作のコールバックをいつ実行するかを決定します。この設計により、Node.js はメインスレッドをブロックすることなく複数のリクエストを処理できるようになり、アプリケーションの高いパフォーマンスが保証されます。

イベント ループの 6 つのフェーズ

イベント ループは周期的に動作し、6 つの異なるフェーズを通過します。各フェーズには特定の目的があり、コールバックはそれに応じて実行されます。

1.タイマーフェーズ

このフェーズでは、setTimeout と setInterval によってスケジュールされたコールバックを実行します。指定された遅延時間が経過すると、関連するコールバックがここで実行されます。

:

setTimeout(() => {
  console.log('Executed after 1 second.');
}, 1000);
console.log('Timer scheduled.');
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

出力:

Timer scheduled.
Executed after 1 second.
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

遅延が 1000 ミリ秒 であっても、setTimeout は現在のイベント ループ ティックが完了した後に実行されます。

setInterval の例

let count = 0;
const intervalId = setInterval(() => {
  console.log(`Interval executed: ${++count}`);
  if (count === 3) clearInterval(intervalId);
}, 500);
ログイン後にコピー
ログイン後にコピー

2.コールバック保留フェーズ

このフェーズでは、イベント ループは前のサイクルから延期された I/O コールバックを処理します。これらのコールバックは、エラーとノンブロッキング I/O 操作を処理します。

:

const fs = require('fs');
fs.readFile('file.txt', (err, data) => {
  if (err) console.error(err);
  else console.log(data.toString());
});
ログイン後にコピー
ログイン後にコピー

出力:

Read operation scheduled.
File content:<contents of example.txt>
ログイン後にコピー
ログイン後にコピー

3.アイドル、準備フェーズ

このフェーズは、次のポーリング ラウンドに向けてシステムを準備するために Node.js によって内部的に使用されます。このフェーズと直接対話することはありませんが、内部ポーリングの設定などのタスクに焦点を当てることで、このフェーズに関連するいくつかの動作をシミュレートできます。

TCP サーバー設定の例 (準備状態)

const net = require('net');
const server = net.createServer((socket) => {
  socket.end('Connection closed.');
});

server.listen(8080, () => {
  console.log('Server listening on port 8080.');
});
ログイン後にコピー
ログイン後にコピー

準備フェーズでは、このサーバーを初期化します。準備が完了すると、受信接続を待つポーリング フェーズに移行します。

4.ポーリングフェーズ

ポーリングフェーズ中、イベント ループは新しい I/O イベントを待機し、関連するコールバックを実行します。保留中のイベントがない場合は、新しいイベントが発生するかタイマーの実行準備が整うまで、このフェーズに留まります。

setTimeout(() => {
  console.log('Executed after 1 second.');
}, 1000);
console.log('Timer scheduled.');
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ここで、サーバーは HTTP リクエストを待つポーリングフェーズに入ります。リクエストが到着すると、そのコールバックが実行され、レスポンスが送信されます。

5.チェックフェーズ

check フェーズでは、setImmediate でスケジュールされたコールバックが実行されます。これらのコールバックは、保留中の I/O 操作があるかどうかに関係なく、ポーリング フェーズの後に実行されます。

:

Timer scheduled.
Executed after 1 second.
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

出力:

let count = 0;
const intervalId = setInterval(() => {
  console.log(`Interval executed: ${++count}`);
  if (count === 3) clearInterval(intervalId);
}, 500);
ログイン後にコピー
ログイン後にコピー

6.コールバックを閉じるフェーズ

このフェーズではクリーンアップ操作を処理します。たとえば、socket.on('close') など、ネットワーク接続の終了に関連付けられたコールバックはここで実行されます。

const fs = require('fs');
fs.readFile('file.txt', (err, data) => {
  if (err) console.error(err);
  else console.log(data.toString());
});
ログイン後にコピー
ログイン後にコピー

出力:

Read operation scheduled.
File content:<contents of example.txt>
ログイン後にコピー
ログイン後にコピー

クライアントが切断されると、socket.on('close') コールバックがクローズ コールバック フェーズで実行されます。

イベントループのブロック

イベント ループは非同期操作を効率的に管理するように設計されていますが、ループをブロックするとパフォーマンスが低下する可能性があります。メインスレッドが負荷の高い計算や同期操作でスタックすると、他のコールバックが実行できなくなります。これにより遅延が発生し、アプリケーションが応答しなくなる可能性があります。

メインスレッドで CPU を大量に使用するタスク (大規模な計算など) を実行すると、イベント ループがブロックされます。ワーカー スレッドを使用してブロックを防ぐ方法は次のとおりです。

イベントループのブロック例

const net = require('net');
const server = net.createServer((socket) => {
  socket.end('Connection closed.');
});

server.listen(8080, () => {
  console.log('Server listening on port 8080.');
});
ログイン後にコピー
ログイン後にコピー

出力:

const http = require('http');

const server = http.createServer((req, res) => {
  res.end('Hello from server!');
});

server.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});
ログイン後にコピー

この例では、5 秒のブロック期間中は何も実行できないため、アプリケーションは応答しなくなります。

解決策: ワーカー スレッドの使用

setImmediate(() => {
  console.log('Executed in check phase.');
});

setTimeout(() => {
  console.log('Executed in timers phase.');
}, 0);

console.log('Main code executed.');
ログイン後にコピー

出力:

Main code executed.
Executed in check phase.
Executed in timers phase.
ログイン後にコピー

ここでは、ブロッキング計算が別のスレッドで実行され、イベント ループが他のタスクを処理できるようになります。

イベントループのブロックを回避する方法

CPU を集中的に使用するタスクにはワーカー スレッドを使用します:

Node.js は、画像処理暗号化、または 複雑な計算などのタスクを処理するための ワーカー スレッド モジュールを提供します。これにより、負荷の高い操作を並行して実行し、イベント ループから作業をオフロードできます。

ワーカースレッドの例:

setTimeout(() => {
  console.log('Executed after 1 second.');
}, 1000);
console.log('Timer scheduled.');
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

大きなタスクを小さなチャンクに分割します:

非同期関数または setImmediate を使用して、大きなタスクをより小さなノンブロッキング操作に分割します。

:

Timer scheduled.
Executed after 1 second.
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

結論

イベント ループは Node.js のコア コンポーネントであり、非同期操作を効率的に管理する役割を果たします。 6 つのフェーズ (タイマー、保留中のコールバック、アイドルと準備、ポーリング、チェック、クローズ コールバック) を理解することで、開発者はスムーズに実行されるノンブロッキング コードを作成できます。ただし、大量の計算によるイベント ループのブロックを避けることが重要です。 ワーカー スレッド などのツールを活用すると、アプリケーションの高速性と応答性が確保されます。イベント ループをマスターすると、スケーラブルでパフォーマンスの高い Node.js アプリケーションを構築できるようになります。

以上がNode.js のイベント ループ: 非同期操作の管理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!