2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 单线程无阻塞IO模型在Node.js中的工作方式

单线程无阻塞IO模型在Node.js中的工作方式

时间:2020-07-30 20:39:22

相关推荐

单线程无阻塞IO模型在Node.js中的工作方式

本文翻译自:How the single threaded non blocking IO model works in Node.js

I'm not a Node programmer, but I'm interested in howthe single threaded non blocking IO modelworks.我不是Node程序员,但是我对单线程无阻塞IO模型的工作方式感兴趣。After I read the article 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();});

Here comes a question.这是一个问题。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 which is a sleep statement standing for I/O waiting.当有两个请求A(首先出现)和B(由于只有一个线程)时,服务器端程序将首先处理请求A:执行sql查询,这是代表I / O等待的睡眠语句。And The program is stucked at the I/O waiting, and cannot execute the code which renders the web page behind.并且该程序被卡在I / O等待中,并且无法执行将网页呈现在后面的代码。Will the program switch to request B during the waiting?在等待期间程序会切换到请求B吗?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".但是示例代码的标题说:“除了您的代码之外,所有内容并行运行”。(PS 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?(由于我从没使用过Node,所以我不确定我是否会误解代码。)在等待期间,Node如何将A切换到B?And can you explainthe single threaded non blocking IO modelof Node in a simple way?您能否以简单的方式解释Node的单线程无阻塞IO模型?I would appreciate if you could help me.如果您能帮助我,我将不胜感激。:):)

#1楼

参考:/question/104tN/单线程无阻塞IO模型在Node-js中的工作方式

#2楼

if you read a bit further - "Of course, on the backend, there are threads and processes for DB access and process execution. However, these are not explicitly exposed to your code, so you can't worry about them other than by knowing that I/O interactions eg with the database, or with other processes will be asynchronous from the perspective of each request since the results from those threads are returned via the event loop to your code."如果您进一步阅读-“当然,在后端,有一些线程和进程用于数据库访问和进程执行。但是,这些线程和进程并未显式地暴露给您的代码,因此您不必担心它们,除非知道从每个请求的角度来看,与数据库或其他进程的I / O交互将是异步​​的,因为这些线程的结果是通过事件循环返回到您的代码的。”

about - "everything runs in parallel except your code" - your code is executed synchronously, whenever you invoke an asynchronous operation such as waiting for IO, the event loop handles everything and invokes the callback.关于-“除了代码之外的所有内容并行运行”-您的代码是同步执行的,每当您调用异步操作(如等待IO)时,事件循环都会处理所有内容并调用回调。it just not something you have to think about.它只是您不必考虑的事情。

in your example: there are two requests A (comes first) and B. you execute request A, your code continue to run synchronously and execute request B. the event loop handles request A, when it finishes it invokes the callback of request A with the result, same goes to request B.在您的示例中:有两个请求A(首先出现)和B。您执行请求A,您的代码继续同步运行并执行请求B。事件循环处理请求A,完成后,它将使用调用请求A的回调结果,同样转到请求B。

#3楼

Well, to give some perspective, let me compare node.js with apache.好吧,给出一些观点,让我比较一下node.js和apache。

Apache is a multi-threaded HTTP server, for each and every request that the server receives, it creates a separate thread which handles that request.Apache是​​一个多线程HTTP服务器,对于服务器收到的每个请求,它都会创建一个单独的线程来处理该请求。

Node.js on the other hand is event driven, handling all requests asynchronously from single thread.另一方面,Node.js是事件驱动的,从单个线程异步处理所有请求。

When A and B are received on apache, two threads are created which handle requests.当在apache上收到A和B时,将创建两个线程来处理请求。Each handling the query separately, each waiting for the query results before serving the page.每个都分别处理查询,每个都在为页面提供服务之前等待查询结果。The page is only served until the query is finished.该页面仅在查询完成之前提供。The query fetch is blocking because the server cannot execute the rest of thread until it receives the result.查询提取被阻止,因为服务器直到接收到结果后才能执行其余线程。

In node, c.query is handled asynchronously, which means while c.query fetches the results for A, it jumps to handle c.query for B, and when the results arrive for A arrive it sends back the results to callback which sends the response.在节点中,c.query是异步处理的,这意味着,当c.query获取A的结果时,它跳到为B处理c.query,当结果到达A时,它将结果发送回回调,该回调发送响应。Node.js knows to execute callback when fetch finishes.Node.js知道在提取完成时执行回调。

In my opinion, because it's a single thread model, there is no way to switch from one request to another.我认为,因为它是单线程模型,所以无法从一个请求切换到另一个请求。

Actually the node server does exactly that for you all the time.实际上,节点服务器一直在为您执行此操作。To make switches, (the asynchronous behavior) most functions that you would use will have callbacks.为了进行切换,(异步行为)您将使用的大多数函数将具有回调。

Edit编辑

The SQL query is taken from mysql library.SQL查询取自mysql库。It implements callback style as well as event emitter to queue SQL requests.它实现了回调样式以及事件发射器来对SQL请求进行排队。It does not execute them asynchronously, that is done by the internal libuv threads that provide the abstraction of non-blocking I/O.它不会异步执行它们,这是由内部libuv线程完成的,该内部libuv线程提供了非阻塞I / O的抽象。The following steps happen for making a query :进行查询的步骤如下:

Open a connection to db, connection itself can be made asynchronously.打开到db的连接,连接本身可以异步进行。Once db is connected, query is passed on to the server.连接数据库后,查询将传递到服务器。Queries can be queued.查询可以排队。The main event loop gets notified of the completion with callback or event.主事件循环通过回调或事件获得完成通知。Main loop executes your callback/eventhandler.主循环执行您的回调/事件处理程序。

The incoming requests to http server are handled in the similar fashion.以类似的方式处理对http服务器的传入请求。The internal thread architecture is something like this:内部线程体系结构是这样的:

The C++ threads are the libuv ones which do the asynchronous I/O (disk or network).C ++线程是libuv线程,它们执行异步I / O(磁盘或网络)。The main event loop continues to execute after the dispatching the request to thread pool.在将请求分派到线程池之后,主事件循环继续执行。It can accept more requests as it does not wait or sleep.它可以等待或休眠,因此可以接受更多请求。SQL queries/HTTP requests/file system reads all happen this way.SQL查询/ HTTP请求/文件系统读取都是以这种方式发生的。

#4楼

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).Node.js基于libuv构建 ,该库是一个跨平台的库,该库为支持的OS(至少为Unix,OS X和Windows)提供的异步(非阻塞)输入/输出抽象api / syscall。

Asynchronous IO异步IO

In this programming model open/read/write operation on devices and resources (sockets, filesystem, etc.) managed by the file-systemdon'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.在此编程模型中,对由文件系统管理的设备和资源(套接字,文件系统等)的打开/读取/写入操作不会阻塞调用线程(就像在典型的同步c状模型中一样),而只是标记当有新数据或事件可用时,将通知该进程(在内核/ OS级数据结构中)。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.如果是类似Web服务器的应用程序,则该过程负责确定通知事件属于哪个请求/上下文,并从那里继续处理请求。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.请注意,这必然意味着您将与向OS发起请求的堆栈位于不同的堆栈框架上,因为OS必须屈服于进程的调度程序才能使单线程进程处理新事件。

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."“您需要在函数A中发出请求,并在另一个函数中处理结果,而在该函数中,通常无法使用A中的本地人。

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

Moreover, after invoking a function spawning an IO operation the calling function will usuallyreturncontrol to node'sevent loop.此外,在调用产生了IO操作的函数后,调用函数通常会将控制权return到节点的事件循环。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 assomewhat 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.您可以认为节点的事件循环与内核的调度程序有些相似:内核将在其未完成的IO完成后调度执行阻塞的线程,而节点将在发生相应事件时调度回调。

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 fromhundreds of thousands open socket with a single threadconcurrently 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? ).最后,短语“除了代码之外的所有内容并行运行”在捕获节点这一点上做得很不错,该节点允许您的代码通过多路复用和排序所有js并通过一个线程同时处理来自成千上万个开放套接字的请求单个执行流中的逻辑(即使说“一切并行运行”在这里可能不正确-请参阅并发与并行-有什么区别? )。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.这对于webapp服务器非常有效,因为实际上大部分时间都花在等待网络或磁盘(数据库/套接字)上,并且逻辑实际上并不需要占用CPU过多的资源-也就是说:这对于IO受限的工作负载非常有效

#5楼

Okay, most things should be clear so far...the tricky part is the SQL: if it is not in realityrunning in another thread or processin it's entirety, the SQL-execution has to bebroken down into individual steps(by an SQL processor made for asynchronous execution!), where the non-blocking ones are executed, and the blocking ones (eg the sleep) actuallycanbe transferred to the kernel (as an alarm interrupt/event) and put on the event list for the main loop.好的,到目前为止,大多数事情应该都已经清楚了……最棘手的部分是SQL:如果实际上不是在另一个线程或整个进程中整体运行,则必须将SQL执行分解为各个步骤(通过用于异步执行的SQL处理器!),其中执行非阻塞线程,而阻塞线程(例如睡眠)实际上可以传输到内核(作为警报中断/事件),并放入事件列表中。主循环。

That means, eg the interpretation of the SQL, etc. is done immediately, but during the wait (stored as an event to come in the future by the kernel in some kqueue, epoll, ... structure; together with the other IO operations) the main loop can do other things and eventually check if something happened of those IOs and waits.这就是说,例如,SQL的解释等是立即完成的,但是在等待期间(由内核以某种kqueue,epoll,...结构存储为将来要发生的事件;以及其他IO操作)主循环可以做其他事情,并最终检查这些IO是否发生了什么并等待。

So, to rephrase it again: the program is never (allowed to get) stuck, sleeping calls are never executed.因此,再次重申一下:程序永远不会(允许被阻塞),从不执行睡眠调用。Their duty is done by the kernel (write something, wait for something to come over the network, waiting for time to elapse) or another thread or process.它们的职责是由内核(写一些东西,等待一些东西通过网络,等待时间过去)或另一个线程或进程来完成的。– The Node process checks if at least one of those duties is finished by the kernel in the only blocking call to the OS once in each event-loop-cycle.–在每个事件循环周期中,Node进程仅在对OS的唯一阻塞调用中检查内核是否至少完成了其中一项职责。That point is reached, when everything non-blocking is done.完成所有非阻塞操作后,就达到了这一点。

Clear?明确?:-):-)

I don't know Node.我不知道Node。But where does the c.query come from?但是c.query是从哪里来的?

#6楼

The function c.query() has two argument函数c.query()有两个参数

c.query("Fetch Data", "Post-Processing of Data")

The operation "Fetch Data" in this case is a DB-Query, now this may be handled by Node.js by spawning off a worker thread and giving it this task of performing the DB-Query.在这种情况下,“获取数据”操作是一个DB-Query,现在可以由Node.js通过产生一个工作线程并赋予它执行DB-Query的任务来处理。(Remember Node.js can create thread internally).(请记住,Node.js可以在内部创建线程)。This enables the function to return instantaneously without any delay这使函数可以立即返回而没有任何延迟

The second argument "Post-Processing of Data" is a callback function, the node framework registers this callback and is called by the event loop.第二个参数“数据的后处理”是一个回调函数,节点框架注册该回调并由事件循环调用。

Thus the statementc.query (paramenter1, parameter2)will return instantaneously, enabling node to cater for another request.因此,语句c.query (paramenter1, parameter2)将立即返回,从而使节点能够满足另一个请求。

PS: I have just started to understand node, actually I wanted to write this as comment to @Philip but since didn't have enough reputation points so wrote it as an answer.PS:我才刚刚开始理解节点,实际上我想将其写为@Philip的注释,但由于信誉不高,因此将其写为答案。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。