NodeJs如何创建非阻塞计算

时间:2012-03-03 12:41:50

标签: node.js asynchronous nonblocking

我正试图在nodejs中创建一个非阻塞的重计算。拿这个例子(从其他东西中删除):

http.createServer(function(req, res) {
    console.log(req.url);
    sleep(10000);
    res.end('Hello World');
}).listen(8080, function() { console.log("ready"); });

可以想象,如果我同时打开2个浏览器窗口,第一个将等待10秒,另一个将等待20,如预期的那样。所以,凭借回调在某种程度上是异步的知识,我取消了睡眠并改为:

doHeavyStuff(function() {
    res.end('Hello World');
});

使用简单定义的函数:

function doHeavyStuff(callback) {
    sleep(10000);
    callback();
}

那当然不起作用......我也尝试定义一个EventEmitter并注册它,但是Emitter的主要功能在发出'done'之前就已经进入了睡眠状态,所以一切都会运行块。

我想知道其他人如何编写非阻塞代码...例如mongojs模块,或者child_process.exec是非阻塞的,这意味着在代码的某处,他们将进程分叉到另一个线程上听听它的事件。我怎样才能在例如漫长的过程中复制这个?

我是否完全误解了nodejs范式? :/

谢谢!

更新:解决方案(排序)

感谢Linus的回答,确实唯一的方法是生成子进程,例如另一个节点脚本:

http.createServer(function(req, res) {
    console.log(req.url);

    var child = exec('node calculate.js', function (err, strout, strerr) {
        console.log("fatto");
        res.end(strout);
    });

}).listen(8080, function() { console.log("ready"); });

calculate.js可以花时间去做它需要的东西并返回。通过这种方式,可以并行运行多个请求。

5 个答案:

答案 0 :(得分:12)

如果不使用节点中的某些IO模块(例如fsnet),则无法直接执行此操作。如果您需要进行长时间运行的计算,我建议您在子进程(例如child_process.fork)或队列中执行此操作。

答案 1 :(得分:5)

我们(微软)刚刚发布了可以与Node.js一起使用的napajs,以便在同一个进程中启用多线程JavaScript场景。

您的代码将如下所示:

var napa = require('napajs');

// One-time setup. 
// You can change number of workers per your requirement. 
var zone = napa.zone.create('request-worker-pool', { workers: 4 });

http.createServer(function(req, res) {
    console.log(req.url);

    zone.execute((request) => {
        var result = null;
        // Do heavy computation to get result from request
        // ...
        return result;
    }, [req]).then((result) => {
        res.end(result.value);
    }
}).listen(8080, function() { console.log("ready"); });

您可以阅读this post了解详情。

答案 2 :(得分:4)

这是对事件循环如何工作的经典误解。

这不是节点特有的 - 如果您在浏览器中有长时间运行的计算,它也会阻塞。这样做的方法是将计算分解为小块,从而产生对事件循环的执行,允许JS环境与其他竞争调用交错,但只有一件事发生在一个时间。

setImmediate演示可能很有启发性,您可以找到here

答案 3 :(得分:3)

如果计算可以拆分为块,则可以安排执行程序每N秒轮询一次数据,然后再运行M秒。或者单独为该任务生成专用子进程,以便主线程不会阻塞。

答案 4 :(得分:0)

尽管这是一篇旧文章(8年前),但请尝试为其添加一些新更新。

  1. 要使Node.js应用程序获得良好的性能,首要任务是永远不要阻止事件循环sleep(10000)方法违反了此规则。这也是Node.js不适合CPU密集型应用程序的原因。由于大量的CPU计算发生在事件循环线程(它也是node.js的主线程和单线程)上,因此会阻塞它。

  2. 从第12版开始,
  3. 多线程编程 work_threads 被引入到node.js生态系统中。与多进程编程相比,它轻巧且开销较小。

  4. 尽管node.js中引入了多线程,但是Node.js仍然基于事件驱动模型和异步非阻塞IO。那是node.js的DNA。