单个请求需要很长时间才能使用这些非阻塞I / O服务器会发生什么?

时间:2011-11-16 20:13:29

标签: node.js nonblocking eventlet

使用Node.js,或eventlet或任何其他非阻塞服务器,当给定请求需要很长时间时会发生什么,是否会阻止所有其他请求?

例如,请求进来,并且计算需要200ms,这将阻止其他请求,例如nodejs使用单个线程。

意味着你的每秒15K会大幅下降,因为计算给定请求的响应需要实际的时间。

但这对我来说似乎不对,所以我问的是究竟发生了什么,因为我无法想象这是怎么回事。

6 个答案:

答案 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个人。如果有人花了太多时间来支付他的账单(从而阻止事件循环),其他人只需要等待轮到他们......等待...

In other words

  

由于事件循环在单个线程上运行,因此非常   重要的是我们不要通过沉重来阻止它的执行   回调函数或同步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