单线程无阻塞IO模型在Node.js中的工作方式 [英] How the single threaded non blocking IO model works in Node.js

查看:126
本文介绍了单线程无阻塞IO模型在Node.js中的工作方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不是Node程序员,但我对单线程无阻塞IO模型的工作方式感兴趣. 在阅读文章了解- 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();
    }
);

队列:当由于只有一个线程而有两个请求A(首先出现)和B时,服务器端程序将首先处理请求A:执行SQL查询是一个睡眠语句代表I/O等待.并且该程序被卡在I/O等待中,并且无法执行将网页呈现在后面的代码.程序在等待期间是否会切换到请求B?我认为,由于是单线程模型,因此无法将一个请求与另一个请求进行切换.但是示例代码的标题显示,除您的代码外,所有内容并行运行.

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

解决方案

Node.js基于 libuv ,这是一个跨平台的库,可为支持的操作系统(至少为Unix,OS X和Windows)提供的异步(非阻塞)输入/输出抽象api/syscall.

异步IO

在此编程模型中,对由文件系统管理的设备和资源(套接字,文件系统等)的打开/读取/写入操作不会阻塞调用线程(通常同步C型模型),并仅在新数据或事件可用时标记要通知的进程(在内核/OS级数据结构中).如果是类似Web服务器的应用程序,则该过程负责确定所通知事件属于哪个请求/上下文,并从那里继续处理该请求.请注意,这必然意味着您将与向OS发出请求的堆栈位于不同的堆栈框架上,因为OS必须屈服于进程的调度程序才能使单线程进程处理新事件.

我描述的模型的问题在于,它对程序员不熟悉且难以推理,因为它本质上是非顺序的. 您需要在函数A中进行请求,并在另一个函数中处理结果,而通常情况下,您无法使用函数A中的本地人."

节点的模型(继续传递样式和事件循环)

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

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

您可以将节点的事件循环视为与内核的调度程序类似:内核将在其未完成的IO完成后调度执行阻塞线程,而节点将在相应事件发生时调度回调已经发生了.

高度并发,没有并行性

最后,短语除了代码之外的所有事物并行运行"在捕捉节点允许您的代码通过单个线程处理来自数十万个开放套接字的请求这一点上做得很出色通过在单个执行流中对所有js逻辑进行多路复用和排序来同时进行(尽管在此处说一切并行运行"可能不正确-参见understanding-the-node-js-event-loop, I'm really confused about it. It gave an example for the model:

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: When there are two request A(comes first) and B since there is only a single thread, the server-side program will handle the request A firstly: doing SQL querying is asleep statement standing for I/O wait. And The program is stucked at the I/O waiting, and cannot execute the code which renders the web page behind. Will the program switch to request B during the waiting? In my opinion, because of the single thread model, there is no way to switch one request from another. But the title of the example code says that everything runs in parallel except your code.

(P.S I'm not sure if I misunderstand the code or not since I have never used Node.)How Node switch A to B during the waiting? And can you explain the single threaded non blocking IO model of Node in a simple way? I would appreciate it if you could help me. :)

解决方案

Node.js is built upon libuv, a cross-platform library that abstracts apis/syscalls for asynchronous (non-blocking) input/output provided by the supported OSes (Unix, OS X and Windows at least).

Asynchronous IO

In this programming model open/read/write operation on devices and resources (sockets, filesystem, etc.) managed by the file-system don't block the calling thread (as in the typical synchronous c-like model) and just mark the process (in kernel/OS level data structure) to be notified when new data or events are available. In case of a web-server-like app, the process is then responsible to figure out which request/context the notified event belongs to and proceed processing the request from there. Note that this will necessarily mean you'll be on a different stack frame from the one that originated the request to the OS as the latter had to yield to a process' dispatcher in order for a single threaded process to handle new events.

The problem with the model I described is that it's not familiar and hard to reason about for the programmer as it's non-sequential in nature. "You need to make request in function A and handle the result in a different function where your locals from A are usually not available."

Node's model (Continuation Passing Style and Event Loop)

Node tackles the problem leveraging javascript's language features to make this model a little more synchronous-looking by inducing the programmer to employ a certain programming style. Every function that requests IO has a signature like function (... parameters ..., callback) and needs to be given a callback that will be invoked when the requested operation is completed (keep in mind that most of the time is spent waiting for the OS to signal the completion - time that can be spent doing other work). Javascript's support for closures allows you to use variables you've defined in the outer (calling) function inside the body of the callback - this allows to keep state between different functions that will be invoked by the node runtime independently. See also Continuation Passing Style.

Moreover, after invoking a function spawning an IO operation the calling function will usually return control to node's event loop. This loop will invoke the next callback or function that was scheduled for execution (most likely because the corresponding event was notified by the OS) - this allows the concurrent processing of multiple requests.

You can think of node's event loop as somewhat similar to the kernel's dispatcher: the kernel would schedule for execution a blocked thread once its pending IO is completed while node will schedule a callback when the corresponding event has occured.

Highly concurrent, no parallelism

As a final remark, the phrase "everything runs in parallel except your code" does a decent job of capturing the point that node allows your code to handle requests from hundreds of thousands open socket with a single thread concurrently by multiplexing and sequencing all your js logic in a single stream of execution (even though saying "everything runs in parallel" is probably not correct here - see Concurrency vs Parallelism - What is the difference?). This works pretty well for webapp servers as most of the time is actually spent on waiting for network or disk (database / sockets) and the logic is not really CPU intensive - that is to say: this works well for IO-bound workloads.

这篇关于单线程无阻塞IO模型在Node.js中的工作方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆