Node.js中单线程非阻塞IO模型的工作原理

Node.js中单线程非阻塞IO模型的工作原理,node.js,Node.js,我不是节点程序员,但我对单线程非阻塞IO模型的工作原理感兴趣。 读完这篇文章后,我真的很困惑。 它给出了模型的一个示例: c.query( 'SELECT SLEEP(20);', function (err, results, fields) { if (err) { throw err; } res.writeHead(200, {'Content-Type': 'text/html'}); res.end('<html

我不是节点程序员,但我对单线程非阻塞IO模型的工作原理感兴趣。 读完这篇文章后,我真的很困惑。 它给出了模型的一个示例:

c.query(
   'SELECT SLEEP(20);',
   function (err, results, fields) {
     if (err) {
       throw err;
     }
     res.writeHead(200, {'Content-Type': 'text/html'});
     res.end('<html><head><title>Hello</title></head><body><h1>Return from async DB query</h1></body></html>');
     c.end();
    }
);
c.query(
'选择睡眠(20);',
函数(错误、结果、字段){
如果(错误){
犯错误;
}
res.writeHead(200,{'Content-Type':'text/html'});
res.end('HelloReturn from async DB query');
c、 end();
}
);
Que:当有两个请求A(首先出现)和B时,由于只有一个线程,服务器端程序将首先处理请求A:执行SQL查询是代表I/O等待的休眠语句。程序在
I/O
等待时受阻,无法执行导致网页落后的代码。在等待过程中,程序是否会切换到请求B?在我看来,由于单线程模型,无法从一个请求切换到另一个请求。但是示例代码的标题说,除了您的代码之外,所有东西都是并行运行的

(p.S.我不确定我是否误解了代码,因为我已经误解了 从未使用过节点。)在等待过程中,节点如何将A切换到B?而且可以 您将解释中节点的单线程非阻塞IO模型 简单的方法?如果您能帮助我,我将不胜感激。:)


如果你读得再深入一点-“当然,在后端,有用于DB访问和进程执行的线程和进程。但是,这些不会显式地暴露于您的代码中,因此您不必担心它们,除非知道从每个请求的角度来看,I/O交互(例如与数据库或其他进程的交互)是异步的,因为这些线程的结果通过事件循环返回到您的代码。”

about—“除了代码之外,所有东西都是并行运行的”-您的代码是同步执行的,每当您调用异步操作(如等待IO)时,事件循环会处理所有东西并调用回调。这不是您必须考虑的事情


在您的示例中:有两个请求A(首先出现)执行请求A,代码继续同步运行并执行请求B。事件循环处理请求A,当它完成时,调用请求A的回调,结果也会调用请求B。

好吧,让我来比较一下node.js和apache

Apache是一个多线程HTTP服务器,对于服务器接收到的每个请求,它都会创建一个单独的线程来处理该请求

另一方面,Node.js是事件驱动的,从单个线程异步处理所有请求

当在apache上接收到A和B时,将创建两个线程来处理请求。每个线程分别处理查询,每个线程在服务页面之前等待查询结果。只有在查询完成后才能服务页面。查询提取被阻塞,因为服务器在收到结果之前无法执行线程的其余部分。

在node中,c.query是异步处理的,这意味着当c.query获取A的结果时,它会跳到处理B的c.query,当A的结果到达时,它会将结果发送回回调,回调发送响应。node.js知道在获取完成时执行回调

在我看来,因为它是一个单线程模型,所以没有办法 从一个请求切换到另一个请求

实际上,节点服务器一直都在为您这样做。要进行切换,(异步行为),您将使用的大多数函数都会有回调

编辑 SQL查询取自库。它实现了回调样式以及事件发射器来对SQL请求进行排队。它不会异步执行SQL请求,这是由提供非阻塞I/O抽象的内部线程完成的。进行查询时,会执行以下步骤:

  • 打开到db的连接,可以异步建立连接本身
  • 连接数据库后,查询将传递到服务器。查询可以排队
  • 主事件循环通过回调或事件获得完成通知
  • 主循环执行回调/事件处理程序
  • 对http服务器的传入请求以类似的方式处理。内部线程体系结构如下所示:

    C++线程是异步异步I/O(磁盘或网络)的线程。。在将请求分派到线程池后,主事件循环将继续执行。它可以接受更多请求,因为它不等待或睡眠。SQL查询/HTTP请求/文件系统读取都是以这种方式发生的。

    Node.js是基于一个跨平台库构建的,它为异步(非阻塞)抽象API/syscalls由受支持的操作系统(至少包括Unix、OS X和Windows)提供的输入/输出

    异步io 在这个编程模型中,文件系统管理的设备和资源(套接字、文件系统等)上的打开/读/写操作不会阻塞调用线程(如典型的同步类c模型),只需标记进程(在内核/OS级数据结构中)当新数据或事件可用时收到通知。如果是web服务器之类的应用程序,则流程负责确定通知事件所属的请求/上下文,并从中继续处理请求。请注意,这必然意味着您将位于与发起请求的堆栈帧不同的堆栈帧上对于操作系统,后者必须屈服于进程的调度程序,以便单线程进程处理新事件

    我所描述的模型的问题是,它对程序员来说并不熟悉,也很难推理,因为它本质上是非顺序的
    c.query("Fetch Data", "Post-Processing of Data")