关于nodejs线程的一些困惑

时间:2016-05-19 07:33:21

标签: node.js asynchronous

我对nodejs主题有一些疑惑。

据我所知,nodejs正在一个线程中运行。如果调用了异步函数,nodejs将创建一个新线程来运行这些异步代码。异步代码完成后。 event loop将获得异步结果并在另一个新线程中触发回调函数。

为了测试,我进行了以下代码测试:

var fs = require("fs");

fs.readFile('package.json','utf-8', function (err, data) {
    if(err)
        console.log(err)
    else
        console.log(data);
});

console.log("before loop");
while(true);
console.log("after loop");

我的预期结果是:

  循环之前

   - - package.json content - -

实际上获取:

  循环之前

在某些地方我可能错了。

问题

  1. 为什么while(true)阻止了readFile()或阻止了它的回调功能?
  2. 这些线程之间的关系是什么?

2 个答案:

答案 0 :(得分:6)

你是正确的,因为nodejs在一个线程中运行。您可以启动单独的进程并在这些进程前放置负载均衡器以使用多核处理器,但这并未在节点本身中实现。

但是,节点不会为它遇到的每个异步函数启动一个线程。它将这些函数调用放入不断运行的事件循环中。这里重要的是事件循环是非阻塞的,这意味着函数调用执行的顺序不能得到保证 - 这就是为什么回调是所有node.js程序的基础的原因。这意味着,例如,当一个函数正在等待在文件系统中找到文件并读取到缓冲区时,事件循环不会停止所有内容以等待它完成并继续下一个调用。但这绝不是多线程行为。事件循环不是并行的任何东西,它只是在任务之间不断切换。这只是多任务处理:)

在您的示例中,while(true)阻止事件循环,因为它不是异步函数调用。不要忘记,javascript中的所有内容都不是异步的 - 只有函数调用可以是异步的,而不是其他语言结构,例如循环或条件。因此,在您的示例中,您运行异步文件读取器,该读取器将添加到事件循环并启动。虽然文件系统正在做它的事情,但事件循环无关,而是转到console.log("在循环之前#34;)消息。之后,使用while(true)循环阻止事件循环。这意味着事件循环不能将其置于保持状态并再次转到文件读取器。

希望能够解决问题。这里的主要内容是,并非javascript中的所有内容都必须是异步的,但是处理不同设备(例如文件系统或网络)的大多数耗时操作都是以非阻塞方式实现的。异步函数仅在使用某些外部组件时才有意义 - 您不会使用异步平方根函数,因为它会阻止事件循环。这就是为什么不建议将node.js用于繁重的计算操作(例如音频/视频编码)的原因 - 异步优势在这里没有意义。

答案 1 :(得分:0)

我在这里找到了一些其他很棒的答案:

调用此回调函数充当调用堆栈中的初始帧,并且由于JavaScript是单线程的,因此在堆栈上的所有调用返回之前,将停止进一步的消息轮询和处理。后续(同步)函数调用向堆栈添加新的调用帧(例如,函数init调用函数changeColor)。

它再次解决了我的困惑!我现在更清楚了!