使用Node.js,或eventlet或任何其他非阻塞服务器,当给定请求需要很长时间时会发生什么,是否会阻止所有其他请求?
例如,请求进来,并且计算需要200ms,这将阻止其他请求,例如nodejs使用单个线程。
意味着你的每秒15K会大幅下降,因为计算给定请求的响应需要实际的时间。
但这对我来说似乎不对,所以我问的是究竟发生了什么,因为我无法想象这是怎么回事。
答案 0 :(得分:7)
它是否“阻止”取决于你对“阻止”的定义。通常,块意味着您的CPU本质上是空闲的,但当前线程无法对其执行任何操作,因为它正在等待I / O等。除非使用非推荐的同步I / O函数,否则在node.js中不会发生这种情况。相反,函数会快速返回,当它们开始完成I / O任务时,会调用您的回调并从那里获取它。在此期间,可以处理其他请求。
如果你在节点中做一些计算量很大的事情,那么在完成之前没有其他任何东西可以使用CPU,但是由于一个非常不同的原因:CPU实际上很忙。通常这不是人们说“阻塞”时的意思,相反,它只是一个很长的计算。
如果它不涉及I / O并且纯粹在进行计算,则需要200ms的时间才能完成。说实话,这可能不是你应该在节点上做的事情。更符合节点精神的解决方案是在节点调用的另一个(非javascript)程序中进行那种数字运算,并在完成时调用您的回调。假设你有一台多核机器(或者另一台程序在另一台机器上运行),节点可以继续响应请求,而另一台程序则会崩溃。有些情况下集群(正如其他人提到的那样)可能有所帮助,但我怀疑你的集群确实是其中之一。如果你有很多很少的请求,而不是CPU的单个核心可以处理的话,那么集群真的是有用的,而不是你有单个请求需要花费数百毫秒的情况。
答案 1 :(得分:1)
你完全正确。如果长时间运行的代码不是异步的,Nodejs开发人员必须意识到这一点,否则他们的应用程序将完全不具备性能。
所有需要“长时间”的事情都需要异步完成。
答案 2 :(得分:1)
node.js中的所有内容在内部并行运行。但是,您自己的代码严格按顺序运行。如果您在node.js中休眠一秒钟,服务器会休眠一秒钟。它不适合需要大量计算的请求。 I / O是并行的,并且您的代码通过回调执行I / O(因此您的代码在等待I / O时没有运行)。
在大多数现代平台上,node.js 我们用于I / O的线程。它使用libev
,它使用最适合平台的线程。
答案 3 :(得分:1)
这基本上是正确的,至少如果您不使用新的cluster
功能来平衡多个自动生成的工作者之间的传入连接。但是,如果您确实使用它,大多数其他请求仍将很快完成。
编辑:工人是流程。
答案 4 :(得分:1)
您可以将事件循环视为排队等候支付账单的10个人。如果有人花了太多时间来支付他的账单(从而阻止事件循环),其他人只需要等待轮到他们......等待...
由于事件循环在单个线程上运行,因此非常 重要的是我们不要通过沉重来阻止它的执行 回调函数或同步I / O中的计算。过了一会 大量的值/对象集合或执行耗时 回调函数中的计算可防止事件循环 进一步处理队列中的其他事件。
答案 5 :(得分:0)
以下是一些实际看到阻止/非阻止操作的代码:
使用此示例(长CPU计算任务,非I / O):
var net = require('net');
handler = function(req, res) {
console.log('hello');
for (i = 0; i < 10000000000; i++) { a = i + 5; }
}
net.createServer(handler).listen(80);
如果您在浏览器中执行了2个请求,则服务器控制台中只会显示一个hello
,这意味着第二个请求无法处理,因为第一个请求阻止了节点.js thread。
如果我们改为执行I / O任务(在磁盘上写入2 GB的数据,在测试过程中需要几秒钟,即使在SSD上):
http = require('http');
fs = require('fs');
buffer = Buffer.alloc(2*1000*1000*1000);
first = true;
done = false;
write = function() {
fs.writeFile('big.bin', buffer, function() { done = true; });
}
handler = function(req, res) {
if (first) {
first = false;
res.end('Starting write..')
write();
return;
}
if (done) {
res.end("write done.");
} else {
res.end('writing ongoing.');
}
}
http.createServer(handler).listen(80);
在这里,我们可以看到,只有几秒钟的IO写作任务write
是非阻止的:如果您在此期间执行其他请求,您将会见writing ongoing.
!这证实了众所周知的non-blocking-for-IO features of Node.js。