ホームページ  >  記事  >  ウェブフロントエンド  >  Node.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか?

Node.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか?

青灯夜游
青灯夜游転載
2020-12-29 18:35:395128ブラウズ

次の記事では、nodejs 「マルチスレッド」を使用して同時実行性の高いタスクを処理する方法を紹介します。一定の参考値があるので、困っている友達が参考になれば幸いです。

Node.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか?

関連する推奨事項: 「nodejs ビデオ チュートリアル

ムーアの法則

ムーア法則はインテルの共同創設者ゴードン・ムーアが1965年に提案したもので、集積回路上に収容できる部品の数は18~24か月ごとに2倍になり、性能も1倍に向上するというものだ。つまり、プロセッサー (CPU) のパフォーマンスは約 2 年ごとに 2 倍になります。

ムーアの法則が提案されてから 50 年以上が経過しました。今日、チップ部品が単一原子のスケールに近づくにつれて、ムーアの法則に従うことがますます困難になってきています。

2019 年、NVIDIA CEO の Jen-Hsun Huang 氏は ECS 展示会で次のように述べました。「ムーアの法則は、かつては 5 年ごとに 10 倍、10 年ごとに 100 倍に成長していました。しかし、現在、ムーアの法則は数倍しか成長できません」 "

単一プロセッサ (CPU) のパフォーマンスは、ますますボトルネックに近づいています。このボトルネックを突破するには、 マルチスレッド テクノロジ を最大限に活用する必要があります。これにより、単一または複数の CPU が複数のスレッドを同時に実行して、コンピュータ タスクをより速く完了できます。

Node のマルチスレッド

Javascript はシングルスレッド言語であり、Nodejs は ## を使用することは誰もが知っています。 #Javascript の機能は、イベント駆動型モデルを使用して非同期 I/O を実装し、非同期 I/O の背後にはマルチスレッド スケジューリングがあります。

Node 非同期 I/O の実装については、Pu Ling の「Node.js の詳細な紹介」を参照してください。 言語では、
Goroutine

を作成して新しいスレッドを明示的に呼び出し、環境変数 GOMAXPROCS を通じて同時実行の最大数を制御できます。 Node には、新しいスレッドを明示的に作成できる

API

がありません。Node は、次のようないくつかの非同期 I/O API を実装します。 fs.readFilehttp.request。これらの非同期 I/O の最下層は、新しいスレッドを呼び出して非同期タスクを実行し、イベント駆動モデルを使用して実行結果を取得します。 サーバーサイド開発とツール開発では、マルチスレッド開発の使用が必要になる場合があります。たとえば、マルチスレッドを使用して複雑なクローラー タスクを処理する、マルチスレッドを使用して同時リクエストを処理する、マルチスレッドを使用してファイル処理を行う、など...マルチスレッドを使用する場合は、次のことを制御する必要があります。同時実行の最大数。最大同時実行数は制御されないため、

ファイル記述子

の枯渇によるエラー、帯域幅不足によるネットワーク エラー、ポート制限によるエラーなどが発生する可能性があります。

Node には同時実行の最大数を制御するための

API

や環境変数がないため、次に、数行の簡単なコードを使用して実装します。 。 コードの実装

まず、次のような需要シナリオを想定します。毎日 100 個のナゲット記事をクロールする必要があるクローラーがあります。1 つの記事のクロールが遅すぎる場合です。一度に 100 件の記事をクロールすると、ネットワーク接続が多すぎるため、多くのリクエストが直接失敗します。 次に、それを実装し、毎回 10 件の記事をリクエストし、10 回で完了します。これにより、効率が10倍向上するだけでなく、安定した動作も保証されます。

単一のリクエスト タスクを見てみましょう。コードは次のように実装されています:

const axios = require("axios");

async function singleRequest(article_id) {
  // 这里我们直接使用 axios 库进行请求
  const reply = await axios.post(
    "https://api.juejin.cn/content_api/v1/article/detail",
    {
      article_id,
    }
  );

  return reply.data;
}

デモンストレーションの便宜上、ここでは同じアドレスを 100 回リクエストします。100 個のリクエスト タスクを作成しましょう. コード 実装は次のとおりです:

// 请求任务列表
const requestFnList = new Array(100)
  .fill("6909002738705629198")
  .map((id) => () => singleRequest(id));

次に、同時リクエスト メソッドを実装しましょう。このメソッドは、複数の非同期タスクの同時実行をサポートし、同時実行の最大数を制限できます。タスク プール内のタスクが実行された後、新しい非同期タスクがプッシュされて実行が継続され、タスク プールの使用率が高くなります。コードは次のように実装されます。

const chalk = require("chalk");
const { log } = require("console");

/**
 * 执行多个异步任务
 * @param {*} fnList 任务列表
 * @param {*} max 最大并发数限制
 * @param {*} taskName 任务名称
 */
async function concurrentRun(fnList = [], max = 5, taskName = "未命名") {
  if (!fnList.length) return;

  log(chalk.blue(`开始执行多个异步任务,最大并发数: ${max}`));
  const replyList = []; // 收集任务执行结果
  const count = fnList.length; // 总任务数量
  const startTime = new Date().getTime(); // 记录任务执行开始时间

  let current = 0;
  // 任务执行程序
  const schedule = async (index) => {
    return new Promise(async (resolve) => {
      const fn = fnList[index];
      if (!fn) return resolve();

      // 执行当前异步任务
      const reply = await fn();
      replyList[index] = reply;
      log(`${taskName} 事务进度 ${((++current / count) * 100).toFixed(2)}% `);

      // 执行完当前任务后,继续执行任务池的剩余任务
      await schedule(index + max);
      resolve();
    });
  };

  // 任务池执行程序
  const scheduleList = new Array(max)
    .fill(0)
    .map((_, index) => schedule(index));
  // 使用 Promise.all 批量执行
  const r = await Promise.all(scheduleList);

  const cost = (new Date().getTime() - startTime) / 1000;
  log(chalk.green(`执行完成,最大并发数: ${max},耗时:${cost}s`));
  return replyList;
}

上記のコードからわかるように、同時リクエストに

Node

を使用するための鍵は

Promise.all

、## です。 #Promise.all 複数の非同期タスクを同時に実行できます。 上記のコードでは、max の長さの配列が作成され、対応する数の非同期タスクが配列に配置されます。次に、Promise.all

を使用して、これらの非同期タスクを同時に実行します。単一の非同期タスクが完了すると、新しい非同期タスクがタスク プールから取得されて実行が継続され、効率が最大化されます。

次に、次のコードを使用して実行テストを実行します (コードは次のように実装されます)

(async () => {
  const requestFnList = new Array(100)
    .fill("6909002738705629198")
    .map((id) => () => singleRequest(id));

  const reply = await concurrentRun(requestFnList, 10, "请求掘金文章");
})();
最終的な実行結果は以下のようになります。

#

この時点で、同時リクエストは完了です。次に、さまざまな同時実行の速度をそれぞれテストしてみましょう~ 最初は 1 つの同時実行、つまり同時実行なし (以下に示すように) です。

Node.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか?

11.462 秒かかります。同時実行を使用しない場合、タスクには非常に長い時間がかかります。次に、他の同時実行条件 (以下に示す) でかかる時間を見てみましょう。

Node.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか?

Node.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか?

## 上の図からわかるように、同時実行数が増加するにつれて、タスクの実行速度はますます速くなります。 !これは高い同時実行性の利点であり、効率を数倍、場合によっては数十倍向上させることができます。 Node.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか?

上記の時間のかかるものを詳しく見てみると、同時実行数が増加しても、時間のかかるものにはしきい値があり、完全には倍増できないことがわかります。これは、

NodeNode.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか? が実際には処理するタスクごとにスレッドを開くのではなく、非同期

I/O

タスク用に新しいスレッドを開くだけであるためです。したがって、

Node

は、I/O 集中型タスクの処理には適していますが、CPU (コンピューティング) 集中型タスクには適していません。 この時点で、同時実行性の高いタスクを処理するためのノード「マルチスレッド」の使用の導入が完了しました。プログラムをより完璧にしたい場合は、タスクのタイムアウトやフォールト トレランスのメカニズムも考慮する必要があります。興味があれば、自分で実装することもできます。 プログラミング関連の知識について詳しくは、プログラミング入門をご覧ください。 !

以上がNode.js の「マルチスレッド」は同時実行性の高いタスクをどのように処理しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。