NodeJs how to create a non-blocking computation
我正在尝试在nodejs中创建一个非阻塞的繁重计算。举个例子(去掉其他东西):
1 2 3 4 5 | http.createServer(function(req, res) { console.log(req.url); sleep(10000); res.end('Hello World'); }).listen(8080, function() { console.log("ready"); }); |
可以想象,如果我同时打开两个浏览器窗口,第一个窗口将等待10秒,另一个窗口将等待20秒,如预期的那样。因此,在知道回调是异步的情况下,我删除了睡眠,并将其改为:
1 2 3 | doHeavyStuff(function() { res.end('Hello World'); }); |
使用简单定义的函数:
1 2 3 4 | function doHeavyStuff(callback) { sleep(10000); callback(); } |
那当然不行…我还试图定义一个eventEmitter并注册到它,但是Emitter的主要功能在发出"done"之前就已经有了睡眠,所以一切都将再次运行block。
我想知道其他人是怎么写非阻塞代码的…例如,mongojs模块或子进程exec是非阻塞的,这意味着在代码的某个地方,它们要么在另一个线程上分叉一个进程,然后监听它的事件。我如何在一个有着漫长过程的metod中复制它?
我是否完全误解了Nodejs的模式?:
谢谢!
更新:解决方案(排序)感谢Linus的回答,实际上唯一的方法是生成子进程,例如另一个节点脚本:
1 2 3 4 5 6 7 8 9 | 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可以花时间完成它需要的并返回。这样,就可以说,多个请求将并行运行。
如果不使用节点中的某些IO模块(如
我们(微软)刚刚发布了napajs,它可以与node.js一起工作,在同一进程中实现多线程的javascript场景。
然后,您的代码将如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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"); }); |
你可以阅读这篇文章了解更多细节。
这是对事件循环如何工作的一个典型误解。
这不是节点独有的功能——如果在浏览器中有一个长时间运行的计算,它也会阻塞。实现这一点的方法是将计算拆分为小块,从而为事件循环生成执行,允许JS环境与其他竞争调用交错,但一次只发生一件事。
如果您的计算可以分割成块,您可以安排执行器每N秒轮询一次数据,然后在M秒后再次运行。或者单独为该任务生成专用的子线程,这样主线程就不会阻塞。