【问题标题】:Why is LIBUV needed in Node JS?为什么 Node JS 中需要 LIBUV?
【发布时间】:2019-10-05 22:04:30
【问题描述】:

所以,也许这个问题太菜鸟和新手,但我仍然不知道为什么 LIBUV 在 Node JS 架构中占有一席之地?以上就是我对 NodeJs 架构的理解。

  1. Node Js 基于 V8 构建
  2. V8 能够运行使用 EcmaScript 标准编写的代码。
  3. V8 是用 C++ 编写的。
  4. 因此,如果您想提供任何新功能,我们可以将 V8 嵌入到我们的 C++ 项目中,并使用 C++ 中的新嵌入式 V8 附加新代码。

现在有疑问了,

  1. 由于 V8 支持 EcmaScript Javascript,这意味着它能够运行使用 EcmaScript 标准编写的回调
  2. 所以我们可以在 C++ 中添加用于文件系统访问、HTTP 服务器和 DB 访问的代码,因为 Java 是用 C++ 编写的(如果我错了,请纠正我)并且 Java 有提供该功能的库(头文件)做同样的事情的能力。
  3. 现在,如果我们可以在 C++ 中添加此功能,那么 Libuv 的位置会在 NodeJs 架构中占据什么位置。

提前致谢 快乐编码:)

【问题讨论】:

  • “我们可以在 C++ 中为 [...] 添加代码” - 或者它可以继续使用 libuv。改变有什么好处?目前尚不清楚您认为“C++”具有哪些符合 libuv 目的的“功能”。有许多库可以抽象出特定于平台的操作……但即使 JVM 实现是用 C++ 编写的(我不知道),所使用的代码也可能不适用于 NodeJS,甚至不可用。
  • 那么,V8 运行的是 JS 吗?对(如果我错了,请纠正我),这意味着它可以处理回调,现在为什么不在 V8(在 Cpp 中)中添加代码并完成,libuv 是否提供了任何额外的东西,或者它只是提供相同的和 Node js用它而不是重新发明轮子?
  • libuv 是由 Node.js 发明的 ;-) 所以 libuv 只是 Node.js 很好的打包方式来执行您的建议,即使用 C++ 在 V8 之上提供附加功能。当然,他们可以做不同的事情,但是将可重用的功能分解到一个单独的库中,以便其他项目可以重用它通常是一种很好的做法。
  • 好的,现在我明白为什么他们将 Libuv 添加到整体架构中了。无论如何感谢您的信息。

标签: javascript c++ node.js v8 libuv


【解决方案1】:

查看以下文档 -

https://nodejs.org/en/docs/meta/topics/dependencies/#libuv

另一个重要的依赖是 libuv,一个 C 库,用于 将非阻塞 I/O 操作抽象为一致的接口 所有支持的平台。它提供了处理文件系统的机制, DNS、网络、子进程、管道、信号处理、轮询和 流媒体。它还包括一个线程池,用于为某些人卸载工作 不能在操作系统上异步完成的事情 级别。

综上所述,V8提供了与运行JS文件相关的功能,但要使用网络、文件等系统资源,则使用libuv。它还提供了一个线程模型来访问所提到的资源。

【讨论】:

    【解决方案2】:

    libuv 模块的职责与标准库中的某些特定功能相关。对于一些标准库函数调用,节点 C++ 端和 libuv 决定完全在事件循环之外进行昂贵的计算。他们创建了一个称为 线程池 的东西,线程池是一系列四个线程,可以用于运行计算密集型任务,例如散列函数。

    libuv 默认在这个线程池中创建四个线程。这意味着除了用于事件循环的线程之外,还有四个其他线程可用于卸载需要在我们的应用程序内部进行的昂贵计算。节点标准库中包含的许多函数都会自动使用这个线程池。

    现在这个线程池的存在非常重要。很明显 Node.js 并不是真正的单线程


    Libuv 还允许节点访问操作系统的底层文件系统,例如网络。因此,正如 node 标准库有一些使用 libuv 线程池的函数一样,它也有一些使用通过 libuv 内置到底层操作系统中的代码的函数。

    简单的 Http 请求

    const https=require(“https”)
    const start=Date.now()
    https.request(“https://www.google.com”,res=>{
    res.on(“data”,()=>{} ) 
    res.on(“end”,()=>{console.log(Date.now()-start)  }) }).end()
    

    所以在这种情况下,libuv 看到我们正在尝试发出 HTTP 请求。 libuv 和 node 都没有任何代码来处理与网络请求相关的所有这些低级操作。相反,libuv 将请求委托给底层操作系统。所以实际上是我们的操作系统执行真正的 HTTP 请求 Libuv 用于发出请求,然后它只是等待操作系统发出信号,表明某些响应已经返回到请求。因此,由于 Libuv 将完成的工作委托给操作系统,操作系统本身决定是否制造新的威胁。或者只是一般如何处理发出请求的整个过程。

    【讨论】:

      【解决方案3】:

      如果有人偶然发现这一点,并且由于它对 OP 的问题没有很好的答案,我会尝试解决这个问题。

      TLDR;

      • Javascript 语言不是异步的
      • Javascript 语言不是多线程的
      • 回调本身不是异步的,它们只是将您的代码搭载到异步操作中。

      让我们一一解答你的疑惑。

      1.由于 V8 支持 EcmaScript Javascript,这意味着它能够运行使用 EcmaScript 标准编写的回调。

      回调并不意味着操作是异步的。回调与异步执行无关。回调只是一种搭载函数的方法,以便它在“异步”之后执行。

      // example of synchronous callback
      
      function main(cb) {
        console.log('main code of the function');
        cb(); // callback invocation here
      }
      
      main(function () { 
        console.log('in callback'); 
      });
      
      

      现在是一个异步回调的例子

      function getDataFromNetwork(url, cb) {
        ajaxCall(url).then(cb);
      }
      
      getDataFromNetwork('http://some-endpoint', function (data) {
        console.log(data);
      });
      

      这是一个带有回调的异步调用。这里的 getDataFromNetwork 函数是异步的而不是回调。关键是回调只是在某事之后运行代码的一种机制。在异步操作中,这成为必需品。我们还要怎么做呢?对吧?

      不! 现在我们有 async-await,您可以在异步函数完成后运行代码,而无需使用回调。

      所以你明白了吗?回调不是异步的。这不是拥有 libuv 的意义。

      2.所以我们可以在 C++ 中添加文件系统访问、Http 服务器和 DB 访问的代码,因为有库(头文件)提供了该功能,因为 Java 是用 C++ 编写的(如果我错了,请纠正我)并且 Java 有能力做一样。

      是的,我们可以为文件系统访问、Http 服务器添加大量代码。 但为什么呢?我们已经有很多图书馆可以做到这一点。是的,它已经用 C 语言编写了,这就是 NodeJS 执行它们的方式。

      Java 已经有了? 没错,但这也是 JVM 的一部分,而不是核心 Java 语言,就像 libuv 是 NodeJS 运行时的一部分,而不是核心 Javascript 语言一样。在这方面,Java 和 NodeJS 是相似的。只是 Java 有自己的 C++ 层,而 NodeJS 为此借用了 libuv。 BTW libuv 主要是为 NodeJS 构建的

      3.现在,如果我们可以在 C++ 中添加这些功能,那么 Libuv 在 NodeJs 架构中的位置在哪里?

      我已经回答了这些功能是如何在 C++ 中实现的,现在让我们看看 libuv 在整个架构的这张图片中的位置。

      让我们以 ajax/网络调用为例。你认为这是谁执行的?

      NodeJS?不,它只是给它的 C++ API(Node API)提供指令。

      那么它是 Node API 吗?不,它只是给 libuv 提供指令

      那么它是 libuv 吗?是的,是的

      计时器、文件访问、子进程等也是如此。

      还想一想,当在 NodeJS 程序中触发大量网络调用、文件访问时,它在哪个进程上运行?谁安排他们?谁通知结果和失败。

      这有很多事情要做。 Java 有自己的线程池来做到这一点。 Java 有自己的调度程序来调度线程。并且因为 Java 也为最终用户(程序员)提供线程。使用 Java 线程实现所有这些东西是有意义的。

      但是 NodeJS 是单线程的。当它可以从另一个库中借用它而不使它们成为 Javascript 的一部分时,为什么它应该有线程来执行 I/O 操作?毕竟,我们不会为程序员提供线程,何必呢?

      此外,从历史上看,Javascript 仅用于在浏览器中运行。浏览器唯一可以访问的异步操作是网络请求,没有文件访问,没有数据库。所以我们还没有很多基础可以构建。

      【讨论】:

      • 太好了,解释感谢您抽出宝贵时间 brajmohan 和 dharman.. 谢谢
      猜你喜欢
      • 2021-10-23
      • 1970-01-01
      • 2019-07-07
      • 2018-03-26
      • 2017-09-23
      • 2019-11-04
      • 2021-10-30
      • 1970-01-01
      • 2023-03-30
      相关资源
      最近更新 更多