Node官方指南中的“在不阻止事件循环的情况下进行复杂计算”的问题

时间:2019-04-12 05:37:36

标签: node.js

Node.js官方指南中的

Complex calculations without blocking the Event Loop”部分建议使用“分区”策略在进行复杂计算时保持事件循环畅通。

为了说明这一点,该指南提供了一个以异步方式计算平均值的示例:

function asyncAvg(n, avgCB) {
  // Save ongoing sum in JS closure.
  var sum = 0;
  function help(i, cb) {
    sum += i;
    if (i == n) {
      cb(sum);
      return;
    }

    // "Asynchronous recursion".
    // Schedule next operation asynchronously.
    setImmediate(help.bind(null, i+1, cb));
  }

  // Start the helper, with CB to call avgCB.
  help(1, function(sum){
      var avg = sum/n;
      avgCB(avg);
  });
}

asyncAvg(n, function(avg){
  console.log('avg of 1-n: ' + avg);
});

相反,同步方式:

for (let i = 0; i < n; i++) {
   sum += i
};

let avg = sum / n;
console.log('avg: ' + avg);

我想出了一些试验来帮助自己弄清这两种方式背后的逻辑,但是却遇到了问题。

我对代码做了一些简单的更改:

异步平均:

function asyncAvg(n, avgCB) {

  // function call time - used to report how long it takes to finish the averaging task
  const startAt = new Date();

  let sum = 0;

  function help(i, cb) {
    sum += i;
    if (i === n) {
      cb(sum);
      return;
    }
    setImmediate(help.bind(null, i + 1, cb));
  }

  help(1, (sum) => avgCB(sum / n, startAt));
}

和同步的:

function syncAvg(n) {
  const start = new Date();

  let sum = 0, i = 0;
  while (i < n) {
    i += 1;
    sum += i;
  }
  console.log(`avg: ${sum / n}, after: ${new Date() - start}ms.`);
}

进行试用:

// function to log out some texts to see the blocking/unblocking effect

function hiMark() {
  const timer = new Date();
  console.log("Oh, hi Mark!");
  return function heyJohny() {
    const delta = new Date() - timer;
    console.log("What's up Johnny." + " [delay: " + delta + "ms]");
  }
}

function main(flag) {

  const N = 100000;

  if (flag === 0) {
    console.log("------ async:");
    let replayHiMark = hiMark();
    asyncAvg(N, (avg, start) => console.log(`avg: ${avg}, after: ${new Date() - start}ms.`));
    replayHiMark();
    console.log("------\n\n");
  } else if (flag === 1) {
    console.log("------ sync:");
    let replayHiMark = hiMark();
    syncAvg(N, "sync A");
    replayHiMark();
    console.log("------\n\n");
  }
}

main(0);
main(1);

结果:

------ async:
Oh, hi Mark!
What's up Johnny. [delay: 0ms]
------


------ sync:
Oh, hi Mark!
avg: 50000.5, after: 2ms.
What's up Johnny. [delay: 3ms]
------


avg: 50000.5, after: 185ms.

的确,有趣的是,使平均异步有助于消除两条文本消息(“无阻塞” I / O)之间的延迟,但与同步同步相比,平均过程也要慢得多(185ms)。只需2毫秒即可完成平均过程;

我是否可以据此得出结论,“分区”策略可以消除阻塞效应,但也可以对计算造成性能损失? 意味着当计算对性能不是很关键时,可以使用它来实现非阻塞I / O,而当同时需要性能和非阻塞I / O时,我不应该考虑使用此策略。

0 个答案:

没有答案