Node.js NodeJs如何创建非阻塞计算

Node.js NodeJs如何创建非阻塞计算,node.js,asynchronous,nonblocking,Node.js,Asynchronous,Nonblocking,我正试图在nodejs中创建一个无阻塞的繁重计算。举个例子(去掉其他东西): 可以想象,如果我同时打开两个浏览器窗口,第一个窗口将等待10秒,另一个窗口将等待20秒,正如预期的那样。因此,在知道回调是异步的情况下,我去掉了睡眠,改为: doHeavyStuff(function() { res.end('Hello World'); }); 对于简单定义的函数: function doHeavyStuff(callback) { sleep(10000); callba

我正试图在nodejs中创建一个无阻塞的繁重计算。举个例子(去掉其他东西):

可以想象,如果我同时打开两个浏览器窗口,第一个窗口将等待10秒,另一个窗口将等待20秒,正如预期的那样。因此,在知道回调是异步的情况下,我去掉了睡眠,改为:

doHeavyStuff(function() {
    res.end('Hello World');
});
对于简单定义的函数:

function doHeavyStuff(callback) {
    sleep(10000);
    callback();
}
那当然不行。。。我还尝试定义一个EventEmitter并注册到它,但是发射器的主要功能在发出“done”之前有一个睡眠,所以所有东西都会运行block

我想知道其他人是如何编写非阻塞代码的。。。例如,mongojs模块或child_process.exec是非阻塞的,这意味着在代码中的某个地方,它们或者在另一个线程上分叉一个进程并侦听其事件。例如,我如何在一个过程漫长的metod中复制这一点

我是否完全误解了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"); });

compute.js可以花时间做它需要的事情并返回。这样,可以说多个请求将并行运行。

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

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

这是对事件循环工作方式的典型误解

这并不是node所独有的—如果您在浏览器中有一个长时间运行的计算,它也会阻塞。实现这一点的方法是将计算分解为小块,这些小块将执行事件循环,允许JS环境与其他竞争调用交错,但一次只发生一件事

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

我们(Microsoft)刚刚发布的一款可以与Node.js一起使用的软件,可以在同一过程中启用多线程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"); });

您可以阅读更多详细信息。

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

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

  • 多线程编程工作线程从版本12开始引入node.js生态系统。与多进程编程相比,它具有轻量级和更少的开销

  • 虽然node.js中引入了多线程,但node.js仍然基于事件驱动模型和异步非块IO。这是node.js的DNA


  • child_进程没有fork()方法,只有exec和spawn。但你是对的,这是避免阻塞一切的唯一方法…给你:。特别是,
    fork
    允许与子进程通信。是的,对。。。我想我坐在一个旧版本的文档上,没有意识到……:)我对这个答案的问题是,您建议在事件循环中运行计算。与阻塞IO调用一样,阻塞计算调用应该在事件循环之外运行,并且使用回调策略处理阻塞计算与阻塞IO调用没有区别。你给它输入并释放它,当它完成后,它会用它的输出给你回电话。现在对于浏览器来说,特别是在没有可用的底层线程池的情况下,像setImmediate这样的库是至关重要的,但是,在浏览器上执行大量计算是例外,而不是规则,而不是手动处理,生成一个子进程可以让操作系统自动并且可能更高效地为您处理这个问题。(如果CPU上有其他可用的内核,它也会使用这些内核。)这允许您的应用程序代码简化为消息传递。对于浏览器,您可以使用Web Worker API。到目前为止,napajs的开发状态如何?取消了吗?还有其他选择吗?
    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"); });