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

时间:2022-04-23 07:19:37

With Node.js, or eventlet or any other non-blocking server, what happens when a given request takes long, does it then block all other requests?

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

Example, a request comes in, and takes 200ms to compute, this will block other requests since e.g. nodejs uses a single thread.

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

Meaning your 15K per second will go down substantially because of the actual time it takes to compute the response for a given request.

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

But this just seems wrong to me, so I'm asking what really happens as I can't imagine that is how things work.

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

6 个解决方案

#1


7  

Whether or not it "blocks" is dependent on your definition of "block". Typically block means that your CPU is essentially idle, but the current thread isn't able to do anything with it because it is waiting for I/O or the like. That sort of thing doesn't tend to happen in node.js unless you use the non-recommended synchronous I/O functions. Instead, functions return quickly, and when the I/O task they started complete, your callback gets called and you take it from there. In the interim, other requests can be processed.

它是否“阻塞”取决于你对“块”的定义。通常,块意味着您的CPU本质上是空闲的,但当前线程无法对其执行任何操作,因为它正在等待I / O等。除非您使用非推荐的同步I / O函数,否则在node.js中不会发生这种情况。相反,函数会快速返回,当它们开始完成的I / O任务时,您的回调会被调用,然后从那里获取它。在此期间,可以处理其他请求。

If you are doing something computation-heavy in node, nothing else is going to be able to use the CPU until it is done, but for a very different reason: the CPU is actually busy. Typically this is not what people mean when they say "blocking", instead, it's just a long computation.

如果你在节点中做了一些计算量很大的事情,那么在完成之前没有其他任何东西可以使用CPU,但是由于一个非常不同的原因:CPU实际上很忙。通常这不是人们说“阻塞”时的意思,相反,它只是一个很长的计算。

200ms is a long time for something to take if it doesn't involve I/O and is purely doing computation. That's probably not the sort of thing you should be doing in node, to be honest. A solution more in the spirit of node would be to have that sort of number crunching happen in another (non-javascript) program that is called by node, and that calls your callback when complete. Assuming you have a multi-core machine (or the other program is running on a different machine), node can continue to respond to requests while the other program crunches away.

如果它不涉及I / O并且纯粹在进行计算,那么200ms是需要很长时间才能完成的。说实话,这可能不是你应该在节点上做的事情。更符合节点精神的解决方案是在节点调用的另一个(非javascript)程序中进行那种数字运算,并在完成时调用回调。假设您有一台多核机器(或另一台程序在不同的机器上运行),节点可以继续响应请求,而另一台程序则会崩溃。

There are cases where a cluster (as others have mentioned) might help, but I doubt yours is really one of those. Clusters really are made for when you have lots and lots of little requests that together are more than a single core of the CPU can handle, not for the case where you have single requests that take hundreds of milliseconds each.

有些情况下集群(正如其他人提到的那样)可能有所帮助,但我怀疑你的集群是其中之一。当你有很多很多小的请求时,集群真的是为了CPU而不是单个核心可以处理,而不是你有单个请求需要花费数百毫秒的情况。

#2


1  

You are exactly correct. Nodejs developers must be aware of that or their applications will be completely non-performant, if long running code is not asynchronous.

你是完全正确的。如果长时间运行的代码不是异步的,Nodejs开发人员必须意识到这一点,否则他们的应用程序将完全不具备性能。

Everything that is going to take a 'long time' needs to be done asynchronously.

所有需要“长时间”的事情都需要异步完成。

#3


1  

Everything in node.js runs in parallel internally. However, your own code runs strictly serially. If you sleep for a second in node.js, the server sleeps for a second. It's not suitable for requests that require a lot of computation. I/O is parallel, and your code does I/O through callbacks (so your code is not running while waiting for the I/O).

node.js中的所有内容都在内部并行运行。但是,您自己的代码严格按顺序运行。如果您在node.js中休眠一秒钟,服务器会休眠一秒钟。它不适合需要大量计算的请求。 I / O是并行的,并且您的代码通过回调执行I / O(因此您的代码在等待I / O时没有运行)。

On most modern platforms, node.js does us threads for I/O. It uses libev, which uses threads where that works best on the platform.

在大多数现代平台上,node.js为I / O提供了线程。它使用libev,它使用最适合平台的线程。

#4


1  

This is basically true, at least if you don't use the new cluster feature that balances incoming connections between multiple, automatically spawned workers. However, if you do use it, most other requests will still complete quickly.

这基本上是正确的,至少如果您不使用新的群集功能来平衡多个自动生成的工作者之间的传入连接。但是,如果您确实使用它,大多数其他请求仍将快速完成。

Edit: Workers are processes.

编辑:工人是流程。

#5


1  

You can think of the event loop as 10 people waiting in line to pay their bills. If somebody is taking too much time to pay his bill (thus blocking the event loop), the other people will just have to hang around waiting for their turn to come.. and waiting...

您可以将事件循环视为排队等候支付账单的10个人。如果有人花了太多时间来支付他的账单(从而阻止事件循环),其他人只需要等待轮到他们......等待......

In other words:

换一种说法:

Since the event loop is running on a single thread, it is very important that we do not block it’s execution by doing heavy computations in callback functions or synchronous I/O. Going over a large collection of values/objects or performing time-consuming computations in a callback function prevents the event loop from further processing other events in the queue.

由于事件循环在单个线程上运行,因此通过在回调函数或同步I / O中进行大量计算来阻止它的执行非常重要。遍历大量值/对象或在回调函数中执行耗时的计算可防止事件循环进一步处理队列中的其他事件。

#6


0  

Here is some code to actually see the blocking / non-blocking in action:

下面是一些实际看到阻塞/非阻塞的代码:

  • With this example (long CPU-computing task, non I/O):

    使用此示例(长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);
    

    if you do 2 requests in the browser, only a single hello will be displayed in the server console, meaning that the second request cannot be processed because the first one blocks the Node.js thread.

    如果你在浏览器中做了2个请求,那么服务器控制台中只会显示一个hello,这意味着第二个请求无法处理,因为第一个请求阻塞了Node.js线程。

  • If we do an I/O task instead (write 2 GB of data on disk, it took a few seconds during my test, even on a SSD):

    如果我们改为执行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);
    

    here we can see that the a-few-second-long-IO-writing-task write is non-blocking: if you do other requests in the meantime, you will see writing ongoing.! This confirms the well-known non-blocking-for-IO features of Node.js.

    在这里,我们可以看到,几秒钟的IO写入任务写入是非阻塞的:如果您同时执行其他请求,您将看到写入正在进行中。这证实了Node.js众所周知的非阻塞IO功能。

#1


7  

Whether or not it "blocks" is dependent on your definition of "block". Typically block means that your CPU is essentially idle, but the current thread isn't able to do anything with it because it is waiting for I/O or the like. That sort of thing doesn't tend to happen in node.js unless you use the non-recommended synchronous I/O functions. Instead, functions return quickly, and when the I/O task they started complete, your callback gets called and you take it from there. In the interim, other requests can be processed.

它是否“阻塞”取决于你对“块”的定义。通常,块意味着您的CPU本质上是空闲的,但当前线程无法对其执行任何操作,因为它正在等待I / O等。除非您使用非推荐的同步I / O函数,否则在node.js中不会发生这种情况。相反,函数会快速返回,当它们开始完成的I / O任务时,您的回调会被调用,然后从那里获取它。在此期间,可以处理其他请求。

If you are doing something computation-heavy in node, nothing else is going to be able to use the CPU until it is done, but for a very different reason: the CPU is actually busy. Typically this is not what people mean when they say "blocking", instead, it's just a long computation.

如果你在节点中做了一些计算量很大的事情,那么在完成之前没有其他任何东西可以使用CPU,但是由于一个非常不同的原因:CPU实际上很忙。通常这不是人们说“阻塞”时的意思,相反,它只是一个很长的计算。

200ms is a long time for something to take if it doesn't involve I/O and is purely doing computation. That's probably not the sort of thing you should be doing in node, to be honest. A solution more in the spirit of node would be to have that sort of number crunching happen in another (non-javascript) program that is called by node, and that calls your callback when complete. Assuming you have a multi-core machine (or the other program is running on a different machine), node can continue to respond to requests while the other program crunches away.

如果它不涉及I / O并且纯粹在进行计算,那么200ms是需要很长时间才能完成的。说实话,这可能不是你应该在节点上做的事情。更符合节点精神的解决方案是在节点调用的另一个(非javascript)程序中进行那种数字运算,并在完成时调用回调。假设您有一台多核机器(或另一台程序在不同的机器上运行),节点可以继续响应请求,而另一台程序则会崩溃。

There are cases where a cluster (as others have mentioned) might help, but I doubt yours is really one of those. Clusters really are made for when you have lots and lots of little requests that together are more than a single core of the CPU can handle, not for the case where you have single requests that take hundreds of milliseconds each.

有些情况下集群(正如其他人提到的那样)可能有所帮助,但我怀疑你的集群是其中之一。当你有很多很多小的请求时,集群真的是为了CPU而不是单个核心可以处理,而不是你有单个请求需要花费数百毫秒的情况。

#2


1  

You are exactly correct. Nodejs developers must be aware of that or their applications will be completely non-performant, if long running code is not asynchronous.

你是完全正确的。如果长时间运行的代码不是异步的,Nodejs开发人员必须意识到这一点,否则他们的应用程序将完全不具备性能。

Everything that is going to take a 'long time' needs to be done asynchronously.

所有需要“长时间”的事情都需要异步完成。

#3


1  

Everything in node.js runs in parallel internally. However, your own code runs strictly serially. If you sleep for a second in node.js, the server sleeps for a second. It's not suitable for requests that require a lot of computation. I/O is parallel, and your code does I/O through callbacks (so your code is not running while waiting for the I/O).

node.js中的所有内容都在内部并行运行。但是,您自己的代码严格按顺序运行。如果您在node.js中休眠一秒钟,服务器会休眠一秒钟。它不适合需要大量计算的请求。 I / O是并行的,并且您的代码通过回调执行I / O(因此您的代码在等待I / O时没有运行)。

On most modern platforms, node.js does us threads for I/O. It uses libev, which uses threads where that works best on the platform.

在大多数现代平台上,node.js为I / O提供了线程。它使用libev,它使用最适合平台的线程。

#4


1  

This is basically true, at least if you don't use the new cluster feature that balances incoming connections between multiple, automatically spawned workers. However, if you do use it, most other requests will still complete quickly.

这基本上是正确的,至少如果您不使用新的群集功能来平衡多个自动生成的工作者之间的传入连接。但是,如果您确实使用它,大多数其他请求仍将快速完成。

Edit: Workers are processes.

编辑:工人是流程。

#5


1  

You can think of the event loop as 10 people waiting in line to pay their bills. If somebody is taking too much time to pay his bill (thus blocking the event loop), the other people will just have to hang around waiting for their turn to come.. and waiting...

您可以将事件循环视为排队等候支付账单的10个人。如果有人花了太多时间来支付他的账单(从而阻止事件循环),其他人只需要等待轮到他们......等待......

In other words:

换一种说法:

Since the event loop is running on a single thread, it is very important that we do not block it’s execution by doing heavy computations in callback functions or synchronous I/O. Going over a large collection of values/objects or performing time-consuming computations in a callback function prevents the event loop from further processing other events in the queue.

由于事件循环在单个线程上运行,因此通过在回调函数或同步I / O中进行大量计算来阻止它的执行非常重要。遍历大量值/对象或在回调函数中执行耗时的计算可防止事件循环进一步处理队列中的其他事件。

#6


0  

Here is some code to actually see the blocking / non-blocking in action:

下面是一些实际看到阻塞/非阻塞的代码:

  • With this example (long CPU-computing task, non I/O):

    使用此示例(长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);
    

    if you do 2 requests in the browser, only a single hello will be displayed in the server console, meaning that the second request cannot be processed because the first one blocks the Node.js thread.

    如果你在浏览器中做了2个请求,那么服务器控制台中只会显示一个hello,这意味着第二个请求无法处理,因为第一个请求阻塞了Node.js线程。

  • If we do an I/O task instead (write 2 GB of data on disk, it took a few seconds during my test, even on a SSD):

    如果我们改为执行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);
    

    here we can see that the a-few-second-long-IO-writing-task write is non-blocking: if you do other requests in the meantime, you will see writing ongoing.! This confirms the well-known non-blocking-for-IO features of Node.js.

    在这里,我们可以看到,几秒钟的IO写入任务写入是非阻塞的:如果您同时执行其他请求,您将看到写入正在进行中。这证实了Node.js众所周知的非阻塞IO功能。