如何使这个Node.js程序异步?

时间:2013-10-02 00:44:56

标签: javascript node.js asynchronous

在下面的javascript程序中(欧拉问题5)我正在练习编写异步/非阻塞功能。该程序试图找到可被数字1-10整除的最小数字。 2520是第一个最小的,这是程序应该停止的地方。

我设置了程序,这样如果函数一起运行,那么第二个checkNum应该先完成并先打印第二个,然后是第一个,但是没有发生?

如何让功能同时运行,而不是一个接一个地运行?我期待来自我调用的第二个checkNum函数的回调首先被调用(因为它开始接近答案),然后是第一个,但这不是发生的事情。非常感谢!

var divides = function(a, b) {
  return b % a == 0;
 };

function checkNum(counter, callback) {
   var noRemainder = 0;
   var forward = true;
    while (forward)
    {
    for (var i = 1; i <= 10; i++) {
         if (divides(i, counter))
          { noRemainder++; }
     }

    if (noRemainder == 10) {
       console.log(counter);
       forward = false;
       callback(counter);
    } else {
      console.log(noRemainder);
      noRemainder = 0;
      counter++;
      console.log(counter);
    }
  }
}

checkNum(1, function(counter) {
             setTimeout(function(){
                        console.log("The counter is: " + counter)},3000) 
              }
);

checkNum(2500, function(counter) {
               setTimeout(function(){
                          console.log("The counter2 is: " + counter) },3000)       

                }
);

3 个答案:

答案 0 :(得分:2)

因为checkNum是一个纯粹的CPU绑定函数 - 也就是说,它唯一能做的就是在紧密的循环中执行计算 - 没有理由让它成为异步的。该功能按定义同步;在计算完成之前,控件不会返回调用者。请考虑以下异步样式:

checkNum(n, function(err, result) {
    console.log(result);
});
console.log('Next line');

...和同步风格:

console.log( checkNum(n) );
console.log('Next line');

在这两种情况下,checkNum的结果将在 之前打印。即使在异步样式中,在checkNum调用其回调并且回调完成之后才会返回控件。 (将此与真正的异步函数进行比较,其中在回调获得结果之前将打印“下一行”。)

节点的真正的魔力来自于一个事实,大多数的的操作(如I / O)是由本地代码在一个单独的线程执行,他们正在做的时候,就调用一个JavaScript主线程上的回调。因此,执行JavaScript所花费的时间非常少,因此您的应用程序执行得非常好。

但是,如果您发现自己在JavaScript中编写了昂贵的循环和类似的计算,则必须记住,您将在函数运行的时间内阻止所有内容。在其他线程上发生的事情将排队,在昂贵的函数返回之前,您的应用程序代码将无法执行任何操作。

根据性能顺序,有几种方法可以解决此限制:

  • 将计算分解为块并使用nextTick开始处理每个块。这允许任何排队的事件在块之间进行处理。
  • 将计算功能移动到单独的文件中,然后启动新进程以实际进行计算。这使得主应用程序在等待结果时可以正常运行。您需要使用fork来执行此操作,因为它带有内置IPC。 Here's an example fibonacci calculator.请记住,这会带来开销:启动新节点进程需要大约30毫秒和至少10 MB的RAM。
  • Actually run your JavaScript code on a separate thread.请注意,代码将与您应用的其余部分隔离开来;您的线程将无法访问主应用程序中的任何变量。这与process -forking方法非常相似,但速度更快,因为您可以避免产生新进程的开销。
  • 在本机(C ++)代码中进行计算,您可以在单独的线程上自由地进行计算。 Here's a native fibonacci example.

答案 1 :(得分:0)

您不能让这些函数真正同时运行,就好像您有多个并行运行的线程一样。这是因为Javascript是单线程,而不是多线程。你真正得到的最好的是“sorta kinda”并行操作,实际上,它并不是平行的。

答案 2 :(得分:0)

您可能希望尝试使用核心cluster模块,这样您就可以为每个核心运行一个节点进程。它可能适用于单核,但强烈建议使用多核来实现此方法。

要检查的另一件事是具有async控制流的parallel模块,尽管这仍然适用于单线程的概念。