当前位置: 首页 > 知识库问答 >
问题:

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

钦楚青
2023-03-14

我不是节点程序员,但我对单线程非阻塞IO模型如何工作感兴趣。在我阅读了理解-the-node-js-event-loop这篇文章之后,我对它真的很困惑。它给出了一个模型的例子:

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();
    }
);

QUE:由于只有一个线程,当有两个请求A(先来)和B时,服务器端程序将首先处理请求A:做SQL查询是sleep语句,代表I/O wait。并且程序被堆放在I/O等待中,无法执行在后面呈现web页面的代码。在等待期间程序会切换到请求B吗?在我看来,由于单线程模型,没有办法从另一个请求中切换一个请求。但是示例代码的标题说,除了您的代码之外,所有的东西都是并行运行的。

(P.S.我不确定我是否误解了代码,因为我从来没有使用过Node。)Node是如何在等待期间将A切换到B的?并且你能用一种简单的方式解释一下Node的单线程无阻塞IO模型吗?如果你能帮助我,我将不胜感激。:)

共有1个答案

彭博厚
2023-03-14

node.js构建于libuv之上,这是一个跨平台的库,它为受支持的操作系统(至少是Unix、OS X和Windows)提供的异步(非阻塞)输入/输出提取API/Syscalls。

在这个编程模型中,对由文件系统管理的设备和资源(套接字、文件系统等)的打开/读/写操作不阻塞调用线程(如典型的同步C类模型中那样),只标记进程(在内核/OS级数据结构中),以便在新数据或事件可用时得到通知。如果是类似Web服务器的应用程序,则流程负责确定通知的事件属于哪个请求/上下文,并从那里继续处理请求。请注意,这必然意味着您将处于一个与向OS发起请求的堆栈帧不同的堆栈帧上,因为后者必须让进程分派程序才能让单线程进程处理新事件。

我描述的模型的问题是程序员不熟悉并且很难推理,因为它在本质上是非顺序的。“您需要在函数A中提出请求,并在另一个函数中处理结果,因为来自A的本地函数通常不可用。”

Node利用JavaScript的语言特性解决了这个问题,通过引导程序员采用某种编程风格,使这个模型看起来更同步。每个请求IO的函数都有一个类似function(...parameters...,callback)的签名,并且需要给出一个回调,该回调将在请求的操作完成时被调用(请记住,大部分时间都花在等待OS发出完成的信号--可以花在做其他工作上的时间)。JavaScript对闭包的支持允许您使用在回调主体内部的外部(调用)函数中定义的变量--这允许在将由节点运行时独立调用的不同函数之间保持状态。另请参见继续传递样式。

此外,在调用产生IO操作的函数之后,调用函数通常将返回控制到节点的事件循环。这个循环将调用计划执行的下一个回调或函数(很可能是因为操作系统通知了相应的事件)--这允许并发处理多个请求

您可以认为node的事件循环有点类似于内核的调度器:一旦挂起的IO完成,内核就会调度阻塞的线程执行,而node则会在相应的事件发生时调度回调。

最后,“除了您的代码之外,所有的东西都并行运行”这句话很好地抓住了这一点,即node允许您的代码通过在单个执行流中复用和排序您的所有js逻辑,同时处理来自数十万个开放套接字的请求(即使在这里说“所有东西都并行运行”可能是不正确的--参见并发与并行--有什么区别?)。这对于webapp服务器非常有效,因为大部分时间实际上都花在等待网络或磁盘(数据库/套接字)上,并且逻辑并不是真正的CPU密集型--也就是说:这对于IO绑定的工作负载非常有效。

 类似资料:
  • 问题内容: 我不是Node程序员,但我对 单线程无阻塞IO模型的 工作方式感兴趣。在阅读了理解理解节点事件循环文章之后,我对此感到非常困惑。它给出了该模型的示例: 队列: 由于只有一个线程,所以有两个请求A(首先出现)和B(首先出现),服务器端程序将首先处理请求A:执行SQL查询是代表I / O等待的sleeping语句。并且该程序被困在等待中,并且无法执行使网页落后的代码。在等待期间程序会切换到

  • 本文向大家介绍python 并发编程 非阻塞IO模型原理解析,包括了python 并发编程 非阻塞IO模型原理解析的使用技巧和注意事项,需要的朋友参考一下 非阻塞IO(non-blocking IO) Linux下,可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子: 从图中可以看出,当用户进程发出read操作时,如

  • 问题内容: Node.JS的最大优点是它具有非阻塞性。它是单线程的,因此不需要为每个新的传入连接生成新的线程。 在事件循环(实际上是单线程)的后面,有一个“非阻塞工作程序”。这个东西不再是单线程的,所以(据我了解),它可以为每个任务产生一个新线程。 也许我误会了一些东西,但是优势到底在哪里。如果要处理的任务很多,那么“非阻塞工作”会不会变成“阻塞工作人员”? 谢谢克里斯蒂安 问题答案: 您需要阅读

  • 非阻塞 IO 仅对在 Servlet 和 Filter(2.3.3.3节定义的,“异步处理”)中的异步请求处理和升级处理(2.3.3.5节定义的,“升级处理”)有效。否则,当调用 ServletInputStream.setReadListener 或ServletOutputStream.setWriteListener 方法时将抛出IllegalStateException。为了支持在 Ser

  • Web 容器中的非阻塞请求处理有助于提高对改善 Web 容器可扩展性不断增加的需求,增加 Web 容器可同时处理请求的连接数量。servlet 容器的非阻塞 IO 允许开发人员在数据可用时读取数据或在数据可写时写数据。非阻塞 IO 仅对在 Servlet 和 Filter(2.3.3.3节定义的,“异步处理”)中的异步请求处理和升级处理(2.3.3.5节定义的,“升级处理”)有效。否则,当调用 S

  • Go提供的网络接口,在用户层是阻塞的,这样最符合人们的编程习惯。在runtime层面,是用epoll/kqueue实现的非阻塞io,为性能提供了保障。 如何实现 底层非阻塞io是如何实现的呢?简单地说,所有文件描述符都被设置成非阻塞的,某个goroutine进行io操作,读或者写文件描述符,如果此刻io还没准备好,则这个goroutine会被放到系统的等待队列中,这个goroutine失去了运行权