简体   繁体   English

node.js 处理阻塞 IO 操作

[英]node.js handling blocking IO operation

I want to understand internal working of node.js, I am intentionally including computation task ( for loop).我想了解 node.js 的内部工作,我有意包括计算任务( for 循环)。 But I see it is still blocking main thread.但我看到它仍然阻塞主线程。

Here is my script这是我的脚本

console.log("start");

for (let i = 0; i < 10; i++) {
    console.log(i)
}

console.log("end")

And the o/p is : start o/p 是:开始

1 1

2 2

3 3

.... ....

10 10

end结尾

But according to node.js architecture shouldn't high computation tasks be executed by different thread picked from thread pool and event loop continue executing non-blocking task?但是根据 node.js 架构,高计算任务不应该由从线程池中选取的不同线程执行,事件循环继续执行非阻塞任务吗? 在此处输入图片说明

I am referencing node.js internal architecture using this link enter link description here我正在使用此链接引用 node.js 内部架构,请在此处输入链接描述

Can someone please explain the architecture and behavior of the script?有人可以解释一下脚本的架构和行为吗?

By default, nodejs uses only ONE thread to run your Javascript with.默认情况下,nodejs 只使用一个线程来运行你的 Javascript。 That means that (unless you engage WorkerThreads which are essentially an entirely separate VM), only one piece of Javascript is ever running at once.这意味着(除非您使用本质上是一个完全独立的虚拟机的 WorkerThreads),一次只能运行一段 Javascript。 Nodejs does not "detect" some long running piece of Javascript and move it to another thread. Nodejs 不会“检测”一些长时间运行的 Javascript 并将其移动到另一个线程。 It has no features like that at all.它根本没有这样的功能。 If you have some long running piece of synchronous Javascript, it will block the event loop and block all other Javascript and all other event processing.如果您有一些长时间运行的同步 Javascript,它将阻塞事件循环并阻塞所有其他 Javascript 和所有其他事件处理。

Internal to its implementation, nodejs has a thread pool that it uses for certain types of native code (internal implementations of file I/O and crypto operations).在其实现内部,nodejs 有一个线程池,用于某些类型的本机代码(文件 I/O 和加密操作的内部实现)。 That only supports the implementation of asynchronous implementations for file I/O and crypto operations - it does not parallelize the running of Javascript.这仅支持文件 I/O 和加密操作的异步实现的实现——它不并行化 Javascript 的运行。

So, your script you show:所以,你展示的脚本:

console.log("start");

for (let i = 0; i < 10; i++) {
    console.log(i)
}

console.log("end")

Is entirely synchronous and runs sequentially and blocks all other Javascript from running while it is running because it is using the one thread for running Javascript while it is running.完全同步并按顺序运行,并在运行时阻止所有其他 Javascript 运行,因为它在运行时使用一个线程来运行 Javascript。

Nodejs gets its excellent scalability from its asynchronous I/O model that does not have to use a separate thread in order to have lots of asynchronous operations in flight at the same time. Nodejs 从其异步 I/O 模型中获得了出色的可扩展性,该模型不必使用单独的线程来同时进行大量异步操作。 But, keep in mind that these asynchronous I/O operations all have native code behind them (some of which may use threads in their native code implementations).但是,请记住,这些异步 I/O 操作背后都有本机代码(其中一些可能在其本机代码实现中使用线程)。

But, if you have long running synchronous Javascript operations (like say something like image analysis written in Javascript), then those typically need to be moved out of the main event loop thread either by shunting them off to WorkerThreads or to other processes or to a native code implementation that may use OS threads.但是,如果您长时间运行同步 Javascript 操作(比如用 Javascript 编写的图像分析之类的东西),那么通常需要将它们移出主事件循环线程,方法是将它们分流到 WorkerThreads 或其他进程或可能使用操作系统线程的本机代码实现。

But according to node.js architecture shouldn't high computation tasks be executed by different thread picked from thread pool and event loop continue executing non-blocking task?但是根据 node.js 架构,高计算任务不应该由从线程池中选取的不同线程执行,事件循环继续执行非阻塞任务吗?

No, that is not how nodejs works and is not a correct interpretation of the diagram you show.不,这不是 nodejs 的工作方式,也不是对您显示的图表的正确解释。 The thread pool is NOT used for running your Javascript.线程池不用于运行您的 Javascript。 It is used for internal implementation of some APIs such as file I/O and some crypto operations.它用于一些 API 的内部实现,例如文件 I/O 和一些加密操作。 It is not used for running your Javascript.它不用于运行您的 Javascript。 There is just one main thread for running your Javascript (unless you specifically run your code in a WorkerThread).只有一个主线程用于运行您的 Javascript(除非您专门在 WorkerThread 中运行您的代码)。

I want to understand internal working of node.js, I am intentionally including computation task ( for loop).我想了解 node.js 的内部工作,我有意包括计算任务( for 循环)。 But I see it is still blocking main thread.但我看到它仍然阻塞主线程。

Yes, a for loop (that does not contain an await statement that is awaiting a promise) will completely occupy the single Javascript thread and will block the event loop from processing other events while the for loop is running.是的, for循环(不包含等待承诺的await语句)将完全占用单个 Javascript 线程,并在for循环运行时阻止事件循环处理其他事件。

There are absolutely no threads in JS (unless you explicitly use worker threads). JS 中绝对没有线程(除非您明确使用工作线程)。 Javascript uses cooperative multi-tasking which means that a function will always complete before the next one will start. Javascript 使用协作式多任务处理,这意味着一个函数总是会在下一个函数开始之前完成。 The only other way to yield control back to the scheduler is to separate a task out into another function that is called asynchronously.将控制权交还给调度程序的唯一其他方法是将任务分离到另一个异步调用的函数中。 So in your example, eg, you could do:所以在你的例子中,例如,你可以这样做:

console.log("start");
setTimeout(() => { 
  for (let i = 0; i < 10; i++) {
    console.log(i)
  }}, 0);
console.log("end")

and you would get:你会得到:

start
end
1
2
..
9

This also answers your question about heavy computations: unless you use the relatively new worker threads , you cannot run heavy computations in node.js "in the background" without the use of native code.这也回答了您关于繁重计算的问题:除非您使用相对较新的工作线程,否则您无法在不使用本机代码的情况下“在后台”在 node.js 中运行繁重的计算。

So if you really have heavy loads you have three options:所以如果你真的有很重的负载,你有三个选择:

  • worker threads,工作线程,
  • native code that is multi-threaded, eg, written in C/C++, or多线程的本机代码,例如,用 C/C++ 编写,或
  • breaking your computation down into small pieces, each one yielding control back to the scheduler when done (eg, using map/reduce).将您的计算分解成小块,每个小块在完成时将控制权交还给调度程序(例如,使用 map/reduce)。

JS executes its code Synchronouse. JS 执行其代码同步。 there are few things that gets "Asynchronouse" like setInterval or setTimout for exmple.例如,很少有像setIntervalsetTimout这样的“异步”的东西。 But thats actually not fully true.但这实际上并不完全正确。 Asynchronouse means things get done in parallel witch is not true.异步意味着事情是并行完成的,但事实并非如此。 Take a look at setTimeout .看看setTimeout By executing it you add the function into the task que, later the event loop grabs it from the que and put it onto the stack and executes it, syncrhonouse.通过执行它,您将函数添加到任务队列中,稍后事件循环从队列中获取它并将其放入堆栈并执行它,同步。 If you want to execute something really parallel then you should consider using an worker thread如果你想执行一些真正并行的事情,那么你应该考虑使用一个工作线程

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM