javascript - 单线程Node.js如何同时处理请求?

标签 javascript node.js single-threaded

我目前正在深入学习Nodejs平台。众所周知,Nodejs是单线程的,并且如果它执行阻塞操作(例如fs.readFileSync),则线程应该等待完成该操作。我决定做一个实验:我创建了一个服务器,该服务器在每次请求时都会从文件中获取大量数据



const { createServer } = require('http');
const fs = require('fs');

const server = createServer();

server.on('request', (req, res) => {
    let data;
    data =fs.readFileSync('./big.file');
    res.end(data);
});

server.listen(8000);





另外,为了启动对服务器的并行请求,我启动了5个终端。我等待看到正在处理一个请求时,其他请求则应等待从第一个请求开始完成阻塞操作。但是,其他4个请求被同时响应。为什么会发生这种现象?

最佳答案

您可能看到的是res.end()内部实现的某个异步部分实际发送大量数据,或者您看到所有数据都非常快速且连续地发送,但是客户端无法快速处理它足以实际按顺序显示它,并且由于客户端各自处于各自独立的过程中,因此它们“出现”以显示并发到达,只是因为它们反应太慢而无法显示实际到达顺序。

人们将不得不使用网络嗅探器来查看实际发生的事件,或者运行一些不同的测试,或者在res.end()的实现中放入一些日志记录,或者在客户端的TCP堆栈中利用某些日志记录来确定数据包到达的实际顺序。在不同的请求中。



如果您有一台服务器,并且有一个正在执行同步I / O的请求处理程序,那么您将不会同时获得多个请求进程。如果您相信这种情况正在发生,那么您将必须准确记录如何衡量或得出结论(以便我们可以帮助您消除误解),因为在使用阻塞式同步I / O时,node.js的工作方式并非如此。作为fs.readFileSync()

node.js以单线程方式运行JS,并且当您使用阻塞的同步I / O时,它将阻塞Javascript的一个线程。这就是为什么永远不要在服务器中使用同步I / O的原因,除非在启动代码中仅在启动期间运行一次。

很明显,fs.readFileSync('./big.file')是同步的,因此直到第一个fs.readFileSync()完成后,您的第二个请求才会开始处理。而且,一次又一次地在同一文件上调用它会非常快(OS磁盘缓存)。

但是,res.end(data)是非阻塞的,异步的。 res是流,您正在为流提供一些要处理的数据。它会通过套接字发送尽可能多的内容,但是如果它受到TCP的流控制,它将暂停直到在套接字上有更多的发送空间。发生多少取决于计算机的各种情况,计算机的配置以及与客户端的网络链接。

因此,可能会发生以下事件序列:


第一个请求到达并执行fs.readFileSync()并调用res.end(data)。这开始将数据发送到客户端,但是由于TCP流量控制而在完成之前返回。这会将node.js发送回其事件循环。
第二个请求到达并执行fs.readFileSync()并调用res.end(data)。这开始将数据发送到客户端,但是由于TCP流量控制而在完成之前返回。这会将node.js发送回其事件循环。
此时,事件循环可能会开始处理第三个或第四个请求,或者它可能会处理更多事件(从res.end()的实现内部或第一个请求的writeStream来继续发送更多数据。如果确实为那些事件提供服务) ,它可以显示(从客户端的角度来看)不同请求的真正并发性。


另外,客户端可能导致其显示为已排序。每个客户端都在读取一个不同的缓冲套接字,如果它们都在不同的终端中,那么它们将是多任务的。因此,如果每个客户端套接字上的数据多于其立即读取和显示的数据(可能是这种情况),则每个客户端将读取一些内容,显示一些内容,读取更多内容,显示更多内容,等等。在服务器上发送每个客户端的响应之间的延迟小于在客户端上读取和显示的延迟,然后客户端(每个客户端在各自独立的进程中)可以并发运行。



当您使用诸如fs.readFile()之类的异步I / O时,正确编写的node.js Javascript代码可以同时“运行”许多请求。它们实际上并不会在完全相同的时间并发运行,但是可以运行,执行一些工作,启动异步操作,然后让其运行另一个请求。使用正确编写的异步I / O,即使在请求处理程序等待异步I / O请求完成时,它看起来更像是共享单个线程,但从外部世界看,并发处理还是很明显的。但是,您显示的服务器代码不是此协作的异步I / O。

关于javascript - 单线程Node.js如何同时处理请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53369763/

相关文章:

javascript - 如何返回 AngularJS 函数的 $http 响应?

javascript - 日历结束日期错了一天

node.js - NestJS:依赖注入(inject)和提供者注册

JavaScript 正则表达式从文本文件中获取标题和副标题

javascript - 出错后继续订阅

javascript - Java套接字io未知传输未定义

javascript - 在 JavaScript 中同时声明变量和函数

java - 用于测试的单线程 Java Websocket

javascript - 如何处理竞争条件

javascript - Node JS 多个并发请求到后端 API