754160
几乎所有提到 Node 的地方, 都强调异步的优越性, 有异步方法, 则尽量不使用同步方法. 强调同步执行的时候会将 node 线程卡住, 导致运行效率下降, 而使用异步方法可以让 node 线程继续执行其他任务, 效率更高.
但是, 请看以下代码. 只是对一段压缩后的字符串进行解压. node 的 zlib 库提供了同步和异步两种 inflate 方法. 这段代码对两种方式的性能做了一个比较. 主要考察每次解压的时间, 单位时间内完成的解压次数, 以及CPU内存开销.
'use strict';
const zlib = require('zlib');
const orgStr = 'Node is similar in design to, and influenced by, systems like Ruby\'s Event Machine or Python\'s Twisted. Node takes the event model a bit further, it presents an event loop as a runtime construct instead of as a library. In other systems there is always a blocking call to start the event-loop. Typically behavior is defined through callbacks at the beginning of a script and at the end starts a server through a blocking call like EventMachine::run(). In Node there is no such start-the-event-loop call. Node simply enters the event loop after executing the input script. Node exits the event loop when there are no more callbacks to perform. This behavior is like browser JavaScript — the event loop is hidden from the user.HTTP is a first class citizen in Node, designed with streaming and low latency in mind. This makes Node well suited for the foundation of a web library or framework.Just because Node is designed without threads, doesn\'t mean you cannot take advantage of multiple cores in your environment. Child processes can be spawned by using our child_process.fork() API, and are designed to be easy to communicate with. Built upon that same interface is the cluster module, which allows you to share sockets between processes to enable load balancing over your cores.';
const compressed = zlib.deflateRawSync(orgStr);
var count = 0;
var timeout = 0;
var res;
function start1() { // sync
let start, i;
setTimeout(start1, 0);
for (i = 0; i < 50; i++) {
start = process.hrtime();
res = zlib.inflateRawSync(compressed);
let end = process.hrtime(start)[1] / 1e6;
if (end > 5) timeout ++; // time interval show below 5 ms
count ++;
}
}
function start2() { // asyncs
(function fn() {
setTimeout(fn, 0);
for (var i = 0; i < 50; i ++) {
let start = process.hrtime();
zlib.inflateRaw(compressed, function (err, buf) {
let end = process.hrtime(start)[1] / 1e6;
if (end > 5) timeout ++;
count ++;
});
}
})();
}
// test start1 for sync or start2 for async
start1();
setInterval(() => {
console.log('timeout : ', timeout + '/' + count);
timeout = 0;
count = 0;
// console.log('mem: ', JSON.stringify(process.memoryUsage()));
}, 1000);
以上是一个遇到的实际问题的抽象. 实际场景下对性能比较敏感. 因此, 我想知道, 为什么这种情况下异步方式看上去完败. 我到底应该使用同步方式来处理这个问题还是用异步方式?