>웹 프론트엔드 >JS 튜토리얼 >node.js '멀티스레딩'은 동시성이 높은 작업을 어떻게 처리합니까?

node.js '멀티스레딩'은 동시성이 높은 작업을 어떻게 처리합니까?

青灯夜游
青灯夜游앞으로
2020-12-29 18:35:395245검색

다음 글에서는 nodejs "멀티스레딩"을 사용하여 동시성 작업을 처리하는 방법을 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

node.js '멀티스레딩'은 동시성이 높은 작업을 어떻게 처리합니까?

관련 추천: "nodejs 비디오 튜토리얼"

무어의 법칙

무어의 법칙은 1965년 인텔 공동 창업자인 고든 무어가 제안한 것, 즉 집적 회로의 수입니다. 수용되는 구성 요소의 수는 18~24개월마다 두 배로 늘어나고 성능도 두 배로 늘어납니다. 즉, 프로세서(CPU) 성능은 약 2년마다 두 배씩 증가합니다.

무어의 법칙이 제안된 지 50년 이상이 지났습니다. 오늘날 칩 구성 요소가 단일 원자 규모에 가까워짐에 따라 무어의 법칙을 따라가는 것이 점점 더 어려워지고 있습니다.

2019년 NVIDIA CEO Jensen Huang은 ECS 전시회에서 다음과 같이 말했습니다. "무어의 법칙은 5년마다 10배, 10년마다 100배씩 성장했습니다. 하지만 이제 무어의 법칙은 매년 몇 퍼센트 포인트씩만 성장할 수 있습니다. 10년." 아마도 2번 정도. 그러므로 무어의 법칙은 끝났다. "

싱글 프로세서(CPU)의 성능이 병목 현상에 가까워지고 있습니다. 이 병목 현상을 돌파하려면 최대한 활용해야 합니다. 멀티스레딩 기술을 사용하면 단일 또는 다중 CPU가 동시에 여러 스레드를 실행하여 컴퓨터 작업을 더 빠르게 완료할 수 있습니다. 多线程技术,让单个或多个 CPU 可以同时执行多个线程,更快的完成计算机任务。

Node 的多线程

我们都知道,Javascript 是单线程语言,Nodejs 利用 Javascript 的特性,使用事件驱动模型,实现了异步 I/O,而异步 I/O 的背后就是多线程调度。

Node 异步 I/O 的实现可以参考朴灵的 《深入浅出 Node.js》

Go 语言中,可以通过创建 Goroutine 来显式调用一条新线程,并且通过环境变量 GOMAXPROCS 来控制最大并发数。

Node 中,没有 API 可以显式创建新线程的 ,Node 实现了一些异步 I/O 的 API,例如 fs.readFilehttp.request。这些异步 I/O 底层是调用了新线程执行异步任务,再利用事件驱动的模式来获取执行结果。

服务端开发、工具开发可能都会需要使用到多线程开发。比如使用多线程处理复杂的爬虫任务,用多线程来处理并发请求,使用多线程进行文件处理等等...

在我们使用多线程时,一定要控制最大同时并发数。因为不控制最大并发数,可能会导致 文件描述符 耗尽引发的错误,带宽不足引发的网络错误、端口限制引发的错误等等。

Node 中并没有用于控制最大并发数的 API 或者环境变量,所以接下来,我们就用几行简单的代码来实现。

代码实现

我们先假设下面的一个需求场景,我有一个爬虫,需要每天爬取 100 篇掘金的文章,如果一篇一篇爬取的话太慢,一次爬取 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.allPromise.all 可以同时执行多个异步任务。

在上面的代码中,创建了一个长度为 max 最大并发数长度的数组,数组里放了对应数量的异步任务。然后使用 Promise.all

Node의 멀티스레딩

우리 모두는 Javascript가 단일 스레드 언어라는 것을 알고 있습니다. NodejsJavascript의 기능을 활용합니다. > 이벤트 중심 모델을 사용합니다. 이 모델은 비동기 I/O를 구현하고 비동기 I/O 뒤에는 다중 스레드 스케줄링이 있습니다.

노드 비동기 I/O 구현에 대해서는 Pu Ling의 "간단한 용어로 Node.js"를 참조할 수 있습니다.
node.js 멀티스레딩은 동시성이 높은 작업을 어떻게 처리합니까?Go에서 언어에서는 Goroutine을 생성하여 새 스레드를 명시적으로 호출하고 환경 변수 GOMAXPROCS를 통해 최대 동시성 수를 제어할 수 있습니다. 🎜노드에는 새 스레드를 명시적으로 생성할 수 있는 API가 없습니다. 노드는 fs.readFile, http.request. 이러한 비동기 I/O의 맨 아래 계층은 새 스레드를 호출하여 비동기 작업을 수행한 다음 이벤트 중심 모델을 사용하여 실행 결과를 얻는 것입니다. 🎜🎜서버측 개발 및 도구 개발에는 멀티스레드 개발을 사용해야 할 수도 있습니다. 예를 들어, 복잡한 크롤러 작업을 처리하기 위해 멀티스레딩을 사용하고, 동시 요청을 처리하기 위해 멀티스레딩을 사용하고, 파일 처리를 위해 멀티스레딩을 사용하는 등...🎜🎜멀티스레딩을 사용할 때는 최대 개수를 제어해야 합니다. 동시 동시성. 최대 동시성 수가 제어되지 않기 때문에 파일 설명자 소진으로 인한 오류, 대역폭 부족으로 인한 네트워크 오류, 포트 제한으로 인한 오류 등이 발생할 수 있습니다. 🎜🎜노드에는 최대 동시성 수를 제어하는 ​​API나 환경 변수가 없으므로 다음으로 간단한 코드 몇 줄을 사용하여 구현하겠습니다. 🎜🎜🎜코드 구현🎜🎜🎜 먼저 매일 100개의 너겟 기사를 크롤링해야 하는 크롤러가 있다고 가정해 보겠습니다. 한 번에 100개의 기사를 크롤링하는 것도 너무 느릴 것입니다. 네트워크 연결이 너무 많기 때문에 많은 요청이 직접 실패합니다. 🎜🎜그러면 매번 10개의 기사를 요청하고 10번 안에 완료하는 식으로 구현할 수 있습니다. 이를 통해 효율성을 10배 높일 수 있을 뿐만 아니라 안정적인 작동도 보장합니다. 🎜🎜단일 요청 작업을 살펴보겠습니다. 코드는 다음과 같이 구현됩니다. 🎜
(async () => {
  const requestFnList = new Array(100)
    .fill("6909002738705629198")
    .map((id) => () => singleRequest(id));

  const reply = await concurrentRun(requestFnList, 10, "请求掘金文章");
})();
🎜여기서는 동일한 주소를 100번 요청합니다. 코드는 다음과 같이 구현됩니다. 🎜rrreee🎜다음으로 동시 요청 방식을 구현해 보겠습니다. 이 방법은 동시에 여러 비동기 작업 실행을 지원하며 최대 동시성 수를 제한할 수 있습니다. 작업 풀의 작업이 실행된 후 작업 풀의 높은 활용도를 보장하기 위해 새로운 비동기 작업이 푸시되어 계속 실행됩니다. 코드는 다음과 같이 구현됩니다. 🎜rrreee🎜위 코드에서 볼 수 있듯이 동시 요청에 Node를 사용하는 핵심은 Promise.all, Promise입니다. .all 여러 비동기 작업을 동시에 실행할 수 있습니다. 🎜🎜위 코드에서는 길이가 max인 배열이 생성되고 해당 배열에 해당 개수의 비동기 작업이 배치됩니다. 그런 다음 Promise.all을 사용하여 이러한 비동기 작업을 동시에 실행합니다. 단일 비동기 작업이 완료되면 작업 풀에서 새로운 비동기 작업이 제거되어 실행이 극대화되어 효율성이 극대화됩니다. 🎜🎜다음으로, 다음 코드를 사용하여 실행 테스트를 수행합니다(코드는 다음과 같이 구현됩니다)🎜rrreee🎜최종 실행 결과는 아래 그림과 같습니다. 🎜🎜🎜🎜

이 시점에서 동시 요청이 완료되었습니다! 다음으로 다양한 동시성 속도를 테스트해보겠습니다~ 첫 번째는 1 동시성, 즉 동시성 없음(아래 그림 참조)

node.js 멀티스레딩은 동시성이 높은 작업을 어떻게 처리합니까?

11.462초가 걸렸습니다! 동시성을 사용하지 않을 경우 작업 시간이 매우 오래 걸립니다. 다음으로 다른 동시성 조건에서 시간이 얼마나 걸리는지 살펴보겠습니다(아래 참조). 위 그림에서 동시성 수가 증가함에 따라 작업 실행 속도가 점점 빨라집니다! 이것이 바로 높은 동시성의 장점으로, 효율성을 여러 번, 경우에 따라 수십 배까지 향상시킬 수 있습니다!

위의 시간 소비를 자세히 살펴보면 동시성 수가 증가함에 따라 시간 소비에는 여전히 임계값이 있으며 완전히 배수로 증가할 수는 없다는 것을 알 수 있습니다. 이는 node.js 멀티스레딩은 동시성이 높은 작업을 어떻게 처리합니까? (계산적으로) 집약적인 작업 때문입니다.

이 시점에서 우리는 높은 동시성 작업을 처리하기 위해 노드 "멀티스레딩" 사용 도입을 마쳤습니다. 프로그램을 더욱 완벽하게 만들고 싶다면 작업 시간 초과 및 내결함성 메커니즘도 고려해야 합니다. 관심이 있다면 직접 구현할 수도 있습니다. node.js 멀티스레딩은 동시성이 높은 작업을 어떻게 처리합니까?

더 많은 프로그래밍 관련 지식을 보려면

프로그래밍 소개node.js 멀티스레딩은 동시성이 높은 작업을 어떻게 처리합니까?를 방문하세요! !

위 내용은 node.js '멀티스레딩'은 동시성이 높은 작업을 어떻게 처리합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제