【问题标题】:NodeJS, Promises and performanceNodeJS,承诺和性能
【发布时间】:2016-10-25 09:37:24
【问题描述】:

我的问题是关于我的 NodeJS 应用程序的性能...

如果我的程序运行 12 次迭代,每次 1.250.000 = 15.000.000 次迭代 - 亚马逊的专用服务器需要以下时间来处理:

r3.large:2 个 vCPU、6.5 个 ECU、15 GB 内存 --> 123 分钟

4.8xlarge:36 个 vCPU、132 个 ECU、60 GB 内存 --> 102 分钟

我有一些类似于下面代码的代码...

start();

start(){

  for(var i=0; i<12; i++){

      function2();    // Iterates over a collection - which contains data split up in intervals - by date intervals. This function is actually also recursive - due to the fact - that is run through the data many time (MAX 50-100 times) - due to different intervals sizes...
    }
}

function2(){

  return new Promise{

    for(var i=0; i<1.250.000; i++){       
         return new Promise{      
            function3();      // This function simple iterate through all possible combinations - and call function3 - with all given values/combinations
         }
      }   
   } 
}


function3(){
   return new Promise{ // This function simple make some calculations based on the given values/combination - and then return the result to function2 - which in the end - decides which result/combination was the best...
}}

这等于每次迭代 0.411 毫秒 / 441 微秒!

当我查看任务栏中的性能和内存使用情况时……CPU 没有以 100% 的速度运行 - 但更像是 50%……整个时间? 内存使用量开始非常低 - 但 KEEPS 以 GB 为单位增长 - 每分钟直到进程完成 - 但是当我在 Windows CMD 中按 CTRL+C 时首先释放(分配的)内存......所以它就像 NodeJS 垃圾收集不能以最佳方式工作 - 或者可能是代码的设计再次简单......

当我执行应用程序时,我使用内存选项:

节点 --max-old-space-size="50000" server.js

请告诉我你能做的每一件事 - 让我的程序更快!

谢谢大家 - 非常感谢!

【问题讨论】:

  • 如果您需要在一个紧密的循环中创建 15M 的 Promise,听起来您应该对应用程序进行大量重组,而不是专注于如何加快该循环的速度。你能提供更多关于你的应用在做什么的信息吗?为什么需要这么多承诺? function3 是做什么的?
  • 首先 - 我是 Node 新手...所以很可能会出现设计错误!简而言之......该程序不使用/访问数据库,不写入磁盘或任何需要多次迭代的东西......它只适用于一些简单的数组/对象......它只是进行大量计算/分析 -在大量数据上...从数据库中获取-在这之前的一步...原因-我使用承诺...是因为节点我设计为异步-尽管这是一个很好的方法做吗?我曾经使用过 .Net/C# 之类的同步代码...
  • 将计算包装在 Promise 中并不一定会使它的性能好很多,尤其是当您创建这么多 Promise 时。如果您在 Google 上搜索 “节点繁重的计算”,您可能会发现一些关于如何在不同的子进程上拆分计算的好方法,利用比单个 Node 进程更多的 CPU 资源。还有various modules可以帮到你。
  • 谢谢你,我明白了......而且我知道我可以做 1000 件事情......但我真的需要一些比我更有经验的人 - 告诉我 - 什么确切的解决方案会对我来说是最好的......我可以轻松地用错误的“解决方案”,框架等再使用一周......我需要具体的代码示例......
  • 我明白了。如果您可以解释您需要执行的计算类型(我假设“12”和“1250000”指的是特定的东西),也许它会让人们更容易帮助您。

标签: node.js performance memory nested-loops es6-promise


【解决方案1】:

并不是垃圾收集器无法以最佳方式工作,而是它根本无法工作 - 你没有给它任何机会。 p>

当在 Node 中开发 tail call 优化 tco module 时,我注意到了一件奇怪的事情。它似乎泄漏了内存,我不知道为什么。原来是因为很少console.log() 在我用来测试的各个地方调用,看看发生了什么,因为看到数百万级深度的递归调用的结果需要一些时间,所以我想在它做的时候看到一些东西。

你的例子和那个很相似。

记住 Node 是单线程的。当您的计算运行时,没有其他东西可以 - 包括 GC。您的代码是完全同步和阻塞的——即使它以阻塞的方式生成数百万个 Promise。它是阻塞的,因为它永远不会到达事件循环。

考虑这个例子:

var a = 0, b = 10000000;

function numbers() {
  while (a < b) {
    console.log("Number " + a++);
  }
}

numbers();

这很简单 - 你想打印 1000 万个数字。但是当你运行它时,它的行为非常奇怪 - 例如,它会打印到某个点的数字,然后它会停止几秒钟,然后它会继续运行,或者如果你正在使用交换,它可能会开始丢弃,或者可能会给你这个错误我刚看到8486号就到了:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Aborted

这里发生的事情是主线程被阻塞在一个同步循环中,它不断创建对象但 GC 没有机会释放它们。

对于如此长时间运行的任务,您需要分工并偶尔进入事件循环。

以下是解决此问题的方法:

var a = 0, b = 10000000;

function numbers() {
  var i = 0;
  while (a < b && i++ < 100) {
    console.log("Number " + a++);
  }
  if (a < b) setImmediate(numbers);
}

numbers();

它的作用相同 - 它打印从 ab 的数字,但以 100 个为一组,然后它安排自己在事件循环结束时继续。

$(which time) -v node numbers1.js 2&gt;&amp;1 | egrep 'Maximum resident|FATAL'的输出

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
    Maximum resident set size (kbytes): 1495968

它使用了 1.5GB 内存并崩溃了。

$(which time) -v node numbers2.js 2&gt;&amp;1 | egrep 'Maximum resident|FATAL'的输出

    Maximum resident set size (kbytes): 56404

它使用了 56MB 内存并完成了。

另请参阅这些答案:

【讨论】:

  • 1.我不打印数百万个console.log...只有1个...最终结果...或者是的-有时...曾经10.000次迭代...最终达到MAX 1000 console.log ...请记住-我的程序在更大的服务器上运行平稳...而不是在我的笔记本电脑上...它遇到内存问题...因为所有“未决”数据/承诺...但是我该如何解决这 - 以最好的方式?
  • @PabloDK console.log 只是一个创建未收集对象的操作示例。在任何情况下,当您阻止事件循环运行时,您都会在 Node 中遇到问题,解决方案通常是将您的任务分成更小的任务。请参阅我的更新答案。如果您详细说明了您正在做什么(计算数字或其他内容)以及创建它们后您想对它们做什么(运行一些回调?将一些统计信息打印到控制台?)我也许可以说更多。跨度>
  • 我明白你的意思...我刚刚在我的代码中添加了一些评论...您能否以我的代码为例...如何“拆分” - 没有“破坏”承诺/解决语句的整个流程?也没有任何其他方式 - 以更好/更快的方式优化执行......比如“多线程”......在具有 36 个内核的亚马逊服务器上会有很大帮助...... ;-)
  • BTW...我的循环结构是这样的...(只看代码)stackoverflow.com/questions/36155096/…
  • 我编写了一些新代码...但在我向您展示之前...它突然将这个错误抛诸脑后!?? immediate._onImmediate 不是一个函数当我用谷歌搜索它时,它与我 NodeJs 的错误有关......??我没有类似名称的代码......我完全按照你告诉我的那样做......代码也执行了 1-2 秒......但是我失败了那个 msg......
猜你喜欢
  • 2019-10-21
  • 2019-09-29
  • 2019-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-16
  • 2020-08-19
相关资源
最近更新 更多