NodeJs如何创建非阻塞计算

Tal*_*ris 17 asynchronous nonblocking node.js

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

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

可以想象,如果我同时打开2个浏览器窗口,第一个将等待10秒,另一个将等待20,如预期的那样.因此,在知道回调以某种方式异步的情况下,我取消了睡眠并将其放入:

doHeavyStuff(function() {
    res.end('Hello World');
});
Run Code Online (Sandbox Code Playgroud)

功能简单定义:

function doHeavyStuff(callback) {
    sleep(10000);
    callback();
}
Run Code Online (Sandbox Code Playgroud)

那当然不起作用......我也尝试定义一个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"); });
Run Code Online (Sandbox Code Playgroud)

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

Lin*_*iel 12

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

  • 在这里:[child_process.fork](http://nodejs.org/docs/latest/api/child_process.html#child_process_child_process_fork_modulepath_args_options).特别是,`fork`允许与子进程进行通信. (3认同)

dmp*_*dmp 5

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

这不是 node 独有的东西 - 如果您在浏览器中有长时间运行的计算,它也会阻塞。这样做的方法是将计算分解成小块,将执行交给事件循环,允许 JS 环境与其他竞争调用交错,但一次只发生一件事。

setImmediate演示可能具有指导意义,您可以在此处找到。


小智 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"); });
Run Code Online (Sandbox Code Playgroud)

您可以阅读这篇文章了解更多详情.