使用 NodeJS 在事件池中处理请求

Requests handling inside Event Pool using NodeJS

我看过多线程机制和NodeJS单线程机制的区别here。我对线程的概念了解较少

我的问题

上面的文章说所有的Non BlockingI/O都是在Event loop中使用单线程处理的

我已经通读了这个论坛上发布的问题,但它所说的只是单线程工作原理的概述,而不是更深层次的机制。说些像... 开始处理客户请求 如果该客户端请求不需要任何阻塞 IO 操作,则处理所有内容,准备响应并将其发送回客户端。

如果事件队列中有 2 个或更多的非阻塞请求,事件循环将获取每个请求并对其进行处理。

第一个请求进入事件池并开始处理,不等待或等待响应,同时请求2进入并开始处理而无需等待。

现在,由于第2个请求已经占用了线程处理(所有请求都使用单线程处理),目前第1个请求处理的是什么,如果有线程共享,如何它发生了吗?

是否在处理第二个请求时释放了第一个请求进程,然后又返回到第一个请求?如果是这样,它在线程方面是如何发生的?

单线程如何同时处理 2 个或更多请求,因为基本上线程将分配给一个请求,直到它的所有进程完成

以及如何同时处理输入和输出操作的单线程?

是否有任何主题我想念以获取此单线程事件循环机制?

首先,"single threaded" 仅适用于 运行 您的 Javascript 的一个线程。 node.js 有其他本地线程来实现内置库中的一些功能。例如,文件I/O使用线程池来实现异步文件I/O。但是,对于了解您自己的 Javascript 运行 的方式,most 重要的是您的 Javascript.

只有一个线程

假设您有一个像这样的简单网络服务器:

const http = require('http');

function sendFile(res, filename) {
    if (filename.startsWith("/")) {
        filename = filename.slice(1) + ".html";
    }
    fs.readFile("1.html", (err, data) => {
       if (err) {
           res.writeHead(404);
           res.end("not found");
       } else {
           res.writeHead(200, {'Content-Type': 'text/html'});
           res.write(data);
           res.end();
       }
    });

}

const server = http.createServer((req, res) => {
    if (req.url === "/1" || req.url === "/2" || req.url === "/3") {
        sendFile(req.url);
    } else {
        res.writeHead(404);
        res.end("not found");
    }
});

server.listen(80);

此 Web 服务器响应对三个 URL /1、/2 和 /3 的请求。

现在假设三个独立的客户端各自请求其中一个 osURL。这是事件的顺序:

  1. 客户端 A 请求 http://myserver.com/1
  2. 客户端 B 请求 http://myserver.com/2
  3. 客户端 C 请求 http://myserver.com/3
  4. 服务器接收来自客户端 A 的传入连接,建立连接,客户端发送对 /1 的请求,服务器读取并解析该请求。
  5. 当服务器忙于读取客户端A的请求时,客户端B和客户端C的请求都到了。
  6. TCP 堆栈在 OS 级别处理传入连接(使用其他线程,即内核级别线程)。
  7. 到达连接的通知放在node.js事件队列中。因为 node.js 服务器正忙 运行 正在为客户端 A 连接 Javascript,所以 os 这两个事件暂时位于事件队列中。
  8. 在os其他连接到达的同时,node.js 服务器开始运行 /1 的请求处理程序。它在第一个 if 语句中找到匹配项并调用 sendFile("/1").
  9. sendFile() 调用 fs.readFile(),然后调用 return。因为fs.readFile()是异步的,所以启动那个文件操作,但是交给node.js里面的I/O系统,然后函数马上returns。当 sendFile() returns 时,它返回到 http 服务器请求处理程序,然后 returns。此时,此请求没有其他可做的事情。控制权已return返回给解释器以决定下一步做什么。
  10. node.js 解释器检查事件队列以查看是否有任何要处理的内容。它找到来自客户端 B 的传入请求并开始处理该请求。此请求经过相同的 8 步和 9 步,直到 return 启动另一个 fs.readFile() 操作。
  11. 然后对来自客户端 C 的传入请求重复步骤 10。
  12. 然后,不久之后,先前启动的三个 fs.readfile() 操作之一完成并将完成回调放入 Javascript 事件队列。一旦 Javascript 解释器无事可做,它就会在事件队列中找到该事件并开始处理它。这将调用传递给 fs.readFile() 的回调函数,并使用该函数期望的两个参数,回调中的代码开始执行。
  13. 假设fs.readFile()操作成功,它调用res.writeHead(),然后res.write(),然后res.send()。 os三个调用都将数据发送到底层 OS TCP 堆栈,然后将数据发送回客户端。
  14. res.end() return 秒后,控制权 return 返回给解释器,它会检查事件队列中的下一个事件。如果另一个 fs.readFile() 回调已经在事件队列中,则将其从事件队列中拉出并像前一个一样处理。如果事件队列为空,则解释器会一直等待,直到有内容放入事件队列。

If there are like 2 or more Non Blocking requests in Event Queue, Event loop takes each requests and processes it.

node.js 一次只有 运行 个。但是,关键是请求处理程序中的异步代码允许处理程序 return 将控制权交还给系统,以便在第一个请求等待其异步操作完成时可以处理其他事件。这是一种合作的、非抢占式的多任务处理形式。不是Javascript的多线程。第一个请求处理程序实际上开始异步操作,然后是 returns(就好像它已完成)。当它 returns 时,队列中的下一个事件可以开始处理。稍后当异步操作完成时,它会将自己的事件插入事件队列,然后重新排队以再次使用 Javascript 的单线程。

First request enter Event Pool and starts processing and does not wait or hold till the response and meanwhile request 2 enters and starts processing without wait.

Most上面已经说了。如果 Javascript 线程忙,为什么请求 2 进入事件队列,该请求将位于事件队列中,直到 Javascript 线程不再忙。它可能需要等待一小段时间。但是,它不必等到请求 1 完成,只需等到请求 1 return 将控制权交还给系统,并且它本身正在等待一些异步操作完成。

Now,since the 2nd request has taken the thread for processing (and all request is handled using single thread) , currently what is handling the 1st request process, If there is thread sharing , how is it happening ?

虽然第二个请求正在使用 Javascript 线程,但第一个请求未 运行 任何 Javascript。它的本机代码异步操作可能在后台 运行ning(所有异步操作都需要一些本机代码),但在任何给定时间只有一段 Javascript 运行ning 所以如果第二个请求是 运行 一些 Javascript,那么第一个请求要么正在等待其异步操作完成,要么该操作已经完成并且事件位于事件队列中等待第二个请求完成后才能处理事件。

Is the first request process released when handling 2nd request and later comes back to 1st request ? if so how is it happening in thread perspective ?

这一切都通过事件队列进行。第一个请求 运行s 直到 returns。第二个请求 运行s 直到 returns。当第一个请求的异步操作完成时,它会在事件队列中插入一个项目。当 JS 解释器空闲时,它会从事件队列中拉出该事件并 运行 发送它。异步操作的本机代码实现可能有线程参与,但仍然只有Javascript.

一个线程

how does single thread processes 2 or more request concurrently as basically thread will be assigned to a request until all it's process is finished

它实际上从未同时 运行 多个 Javascript。来自每个不同操作的 Javascript 运行s 直到它 returns 将控制权交还给解释器。异步操作(例如文件 I/O 或网络操作)可以 运行 并发,并且这些操作 os 由本机代码管理,有时使用额外的线程,有时不使用。文件 I/O 使用线程池实现非阻塞、异步文件 I/O。网络使用 OS 事件通知(select、epoll 等),而不是线程。

and how is single thread handled for both Input and Output operation at same time ?

它不在您的 Javascript 中。它通常会读取,然后写入。它不会同时执行两者 "at the same time"。现在,TCP 堆栈可能在 OS 内部执行一些实际的并行工作,但这全部由 OS 管理,甚至可能在某些 point.Requests 处理时在网络接口上序列化通过单线程,其中输入输出进程由 os 级线程管理,每个进程由 OS

创建

is there any topic i am missing to read so that i'm getting this single thread event loop mechanism ?

阅读您能找到的有关 Javascript 事件队列的所有内容。以下是一些帮助您入门的参考资料:

How does JavaScript handle AJAX responses in the background?