0

在下面的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)       

                }
);
4

3 回答 3

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调用其回调并且回调完成后才会返回控制。(将此与真正的异步函数进行比较,其中“下一行”将在回调得到结果之前打印。)

node 的真正魔力来自于这样一个事实,即最昂贵的操作(如 I/O)是由本机代码在单独的线程上执行的,当它们完成时,它们会在主线程上调用 JavaScript 回调。因此,执行 JavaScript 所花费的时间非常少,因此您的应用程序执行得非常好。

但是,如果您发现自己在 JavaScript 中编写了类似这样的昂贵循环和计算,您必须记住,您将在函数运行期间阻塞所有内容。其他线程上发生的事情将排队,您的应用程序代码将没有机会做任何事情,直到昂贵的函数返回。

有几种方法可以解决此限制,按性能排序:

  • 将计算分成块并用于nextTick开始对每个块的处理。这允许任何排队的事件在块之间进行处理。
  • 将您的计算函数移动到一个单独的文件中,并启动一个新进程来实际进行计算。这使您的主应用程序在等待结果时可以正常运行。你会想用fork它来做这个,因为它带有内置的 IPC。 这是一个示例斐波那契计算器。 请记住,这确实会带来开销:启动一个新的节点进程需要大约 30 毫秒和至少 10 MB 的 RAM。
  • 实际上在单独的线程上运行您的 JavaScript 代码。 请注意,代码将与您的应用程序的其余部分隔离运行;您的线程将无法访问主应用程序中的任何变量。这与进程分叉方法非常相似,但速度更快,因为您避免了产生新进程的开销。
  • 在本机 (C++) 代码中进行计算,您可以在单独的线程上自由地进行计算。 这是一个本地斐波那契示例。
于 2013-10-02T01:28:37.043 回答
0

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

于 2013-10-02T00:49:37.953 回答
0

您可能想尝试一下核心集群模块,这将允许您为每个核心运行一个节点进程。它可能适用于单核,但强烈建议使用多核。

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

于 2013-10-02T01:06:06.523 回答