我正试图在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可以花时间去做它需要的东西并返回。通过这种方式,可以并行运行多个请求。
答案 0 :(得分:12)
如果不使用节点中的某些IO模块(例如fs
或net
),则无法直接执行此操作。如果您需要进行长时间运行的计算,我建议您在子进程(例如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年前),但请尝试为其添加一些新更新。
要使Node.js应用程序获得良好的性能,首要任务是永远不要阻止事件循环。 sleep(10000)
方法违反了此规则。这也是Node.js不适合CPU密集型应用程序的原因。由于大量的CPU计算发生在事件循环线程(它也是node.js的主线程和单线程)上,因此会阻塞它。
多线程编程 work_threads 被引入到node.js生态系统中。与多进程编程相比,它轻巧且开销较小。
尽管node.js中引入了多线程,但是Node.js仍然基于事件驱动模型和异步非阻塞IO。那是node.js的DNA。