Node.js 中的非阻塞或异步 I/O 是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10570246/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:42:21  来源:igfitidea点击:

What is non-blocking or asynchronous I/O in Node.js?

node.jsasynchronousnonblockingserverside-javascript

提问by Anand

In the context of Server Side Javascript engines, what is non-blocking I/O or asynchronous I/O? I see this being mentioned as an advantage over Java server side implementations.

在服务器端 Javascript 引擎的上下文中,什么是非阻塞 I/O 或异步 I/O?我认为这被认为是优于 Java 服务器端实现的优势。

回答by Joseph

Synchronous vs Asynchronous

同步与异步

Synchronous execution usually refers to code executing in sequence. Asynchronous execution refers to execution that doesn't run in the sequence it appears in the code. In the following example, the synchronous operation causes the alerts to fire in sequence. In the async operation, while alert(2)appears to execute second, it doesn't.

同步执行通常是指代码按顺序执行。异步执行是指不按照它在代码中出现的顺序运行的执行。在以下示例中,同步操作会导致警报按顺序触发。在异步操作中,虽然alert(2)看起来是第二次执行,但实际上不是。

Synchronous: 1,2,3

同步:1,2,3

alert(1);
alert(2);
alert(3);

Asynchronous: 1,3,2

异步:1,3,2

alert(1);
setTimeout(() => alert(2), 0);
alert(3);

Blocking vs Non-blocking

阻塞与非阻塞

Blocking refers to operations that block further execution until that operation finishes. Non-blocking refers to code that doesn't block execution. In the given example, localStorageis a blocking operation as it stalls execution to read. On the other hand, fetchis a non-blocking operation as it does not stall alert(3)from execution.

阻塞是指阻止进一步执行直到该操作完成的操作。非阻塞是指不阻塞执行的代码。在给定的示例中,localStorage是一个阻塞操作,因为它会阻止执行读取。另一方面,它fetch是一个非阻塞操作,因为它不会停止alert(3)执行。

// Blocking: 1,... 2
alert(1);
var value = localStorage.getItem('foo');
alert(2);

// Non-blocking: 1, 3,... 2
alert(1);
fetch('example.com').then(() => alert(2));
alert(3);

Advantages

好处

One advantage of non-blocking, asynchronous operations is that you can maximize the usage of a single CPU as well as memory.

非阻塞、异步操作的一个优点是您可以最大限度地利用单个 CPU 和内存。

Synchronous, blocking example

同步、阻塞示例

An example of synchronous, blocking operations is how some web servers like ones in Java or PHP handle IO or network requests. If your code reads from a file or the database, your code "blocks" everything after it from executing. In that period, your machine is holding onto memory and processing time for a thread that isn't doing anything.

同步、阻塞操作的一个例子是一些 Web 服务器(如 Java 或 PHP 中的服务器)如​​何处理 IO 或网络请求。如果您的代码从文件或数据库中读取,则您的代码会“阻止”执行之后的所有内容。在此期间,您的机器为一个不做任何事情的线程占用内存和处理时间。

In order to cater other requests while that thread has stalled depends on your software. What most server software do is spawn more threads to cater the additional requests. This requires more memory consumed and more processing.

为了在该线程停止时满足其他请求取决于您的软件。大多数服务器软件所做的是产生更多线程来满足额外的请求。这需要消耗更多内存和更多处理。

Asynchronous, non-blocking example

异步非阻塞示例

Asynchronous, non-blocking servers - like ones made in Node - only use one thread to service all requests. This means an instance of Node makes the most out of a single thread. The creators designed it with the premise that the I/O and network operations are the bottleneck.

异步的、非阻塞的服务器——就像在 Node 中制作的服务器——只使用一个线程来服务所有的请求。这意味着 Node 的实例可以充分利用单个线程。创作者设计它的前提是I/O和网络操作是瓶颈。

When requests arrive at the server, they are serviced one at a time. However, when the code serviced needs to query the DB for example, it sends the callback to a second queue and the main thread will continue running(it doesn't wait). Now when the DB operation completes and returns, the corresponding callback pulled out of the second queue and queued in a third queue where they are pending execution. When the engine gets a chance to execute something else (like when the execution stack is emptied), it picks up a callback from the third queue and executes it.

当请求到达服务器时,它们一次得到一个服务。但是,例如,当服务的代码需要查询数据库时,它会将回调发送到第二个队列,主线程将继续运行(它不会等待)。现在,当 DB 操作完成并返回时,相应的回调会从第二个队列中拉出并在第三个队列中排队等待执行。当引擎有机会执行其他事情时(例如当执行堆栈被清空时),它会从第三个队列中获取回调并执行它。

回答by Wayne Chiu

var startTime = new Date().getTime();
var getEndTime = () => {
    var tempEndTime = new Date().getTime();
    var second = (tempEndTime - startTime)/1000
    return `took ${second} sec...to finish\n`
}

console.log('1: start App', getEndTime())
setTimeout(()=>{
    console.log('2: setTimeout', getEndTime())
}, 1000)
console.log('3: End App', getEndTime())

// console -> Process Order:  1 -> 3 -> 2

Code example

代码示例