“ 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时,我不应该考虑使用此策略。