表达解决“阻止代码”吗?

时间:2013-04-08 10:56:45

标签: node.js express

我正在学习Node Beginner Book中的node.js和随后的电子书购买。在这本书中,Manuel Kiessling解释了一系列像这样的阻塞代码:

fs.readFileSync(blah);

将阻止整个节点进程和所有请求进入。对于多用户网站来说非常糟糕

这是一个例子,Kiessling使用:

exec("ls -lah", function( error, stdout, stderr ) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write(stdout);
    response.end();
});

这是欺骗我的代码。他说,ls -lah可以很容易地用更耗时的操作替换,如find / -name "*"或数据库查找。我认为由于异步回调,昂贵的阻塞操作会以某种方式在后台显式运行。

所以我用这段代码来测试我的理论:

var http = require("http");
var url = require("url");

badSleep = function(ms) {
    var now = new Date();
    var finishAtDate = now.getTime() + ms;
    console.log("CPU burning sleep for " + ms + " milliseconds");
    while(new Date() < finishAtDate) {
       // do nothing
    }
};

asyncWrapper = function(callback) {
    //badSleep(3000);
    callback();
}

http.createServer(function(request, response) {
    var pathname = url.parse(request.url).pathname;
    console.log("Serve up " + pathname);
    if (pathname == '/favicon.ico') {
        response.writeHead(404);
        response.end();
    } else {
        asyncWrapper(function() {
            badSleep(3000);
            response.writeHead(200, {"Content-Type": "text/plain"});
            response.write("\nI was wrong " + new Date());
            response.end();
        });
    }
}).listen(8888);

问题是,无论我把睡眠放在哪里,仍会阻止节点事件循环。回调确实解决阻塞问题。 SO的好用户也在评论中告诉了我。

那么exec怎么做呢???我很困惑,于是我去看了child-process code at github。我发现exec来电spawn !!!这是一个孩子的过程!谜团已揭开。异步代码没有“解决”阻塞问题,spawn会这样做。

这引出了我的问题。是否以某种方式解决了阻塞问题,还是你还要担心它?

PS:这个问题是一个重要的重写。我想请求以下SO用户的赦免,并感谢他们对我耐心。我肯定在这里学到了一些东西。

3 个答案:

答案 0 :(得分:3)

  

有人发表了关于理解-node-js-event-loop的评论。是   究竟。如果将其包装在异步中,则可以发出阻塞调用   调用,因为你没有阻塞节点事件循环。

如果使用异步调用包装同步调用,您仍将遇到阻塞。例如,如果你写这样的东西:

fs.readFile("file1.txt", function(err, data1) {
   var data2 = fs.readFileSync("file2.txt");
});

由于您正在使用异步调用,因此在读取file1.txt时不会阻止该进程,但是,只要它完成读取file1并且它到达读取file2的行然后它将阻塞即可。

通过在异步/非阻塞调用中发出同步/阻塞调用,您只能延迟阻止。

对于整个网站的阻止非常糟糕,这是正确的,这就是为什么不应经常发出阻止调用的原因。由于node.js是从头开始编写的,因此默认情况下大多数I / O调用都是异步的,您应该尽可能多地使用它们而不是同步调用。

  

问题是,是否会自动为您表达或处理此问题   你还需要担心吗?

你还是要担心它。

答案 1 :(得分:2)

  

问题是,是否会自动为您表达或处理此问题   你还要担心吗?

你还是要担心它。 NodeJS是单线程的,这意味着无论在何处调用,每个同步操作都将完全阻止它。 Express和任何其他框架都不能在不阻塞服务器的情况下使用同步操作。简单

var x = 1;

已经阻止整个服务器,直到它完成创建新变量并为其分配新值。

异步架构的重点在于它比线程更有效。并且不要被愚弄,异步编程比线程更难,因为没有隔离。如果一个线程失败,其他线程仍然有效,而在异步服务器中,一个例外可能会破坏整个服务器。

  

问题是您可以阻止主节点事件循环!

这句话表明NodeJS比主事件循环更多。这不是真的。每个代码都在主循环内调用。

还看看这个:

Event Loop vs Multithread blocking IO

答案 2 :(得分:1)

对非异步函数的任何调用都将“阻塞”,即使它被包装在另一个函数中。唯一的例外是如果包装函数可以将处理推迟到另一个线程/进程(例如,像cluster API)。