Nodejs libuv运行原理详解

 更新时间:2019年08月21日 14:43:34   作者:peiyu1988  
在本篇文章里小编给大家整理的是关于Nodejs libuv运行原理以及相关知识点,有需要的朋友们可以学习下。

前言

这应该是Nodejs的运行原理的第7篇分享,这篇过后,短时间内不会再分享Nodejs的运行原理,会停更一段时间,PS:不是不更,而是会开挖新的坑,最近有在研究RPG Maker MV,区块链,云计算,可能会更新一些相关文章,或者相关教学。

回到正题,异步编程的难点在于请求与响应不是按顺序发生的。以http server 为例,异步编程赋予了server 高并发的品质,而且他可以以很小的资源代价,不断地接受和处理请求。但是快速处理请求不表示快速地返回请求=>高并发不等同于快速反馈。

在Nodejs中,libuv则为异步编程的实现提供了可能。libuv为builtin modules 提供了API,这些API用来支撑请求和数据的返回的异步处理方式。

这一篇分享,我们主要讨论libuv的运行原理,从两个角度出发:

1) libuv的架构

2) 案例,从细节的角度看libuv是如何对待不同I/O请求,按照不同的方式来完成异步请求和数据返回的。

Libuv的架构

从左往右可分为两部分,Network I/O的相关请求,另一部分File I/O,DNS Ops和User Code组成。

上图展示了libuv细节的流程,图中代码很简单,包括2个部分:

1. server.listen()是用来创建TCP server时,通常放在最后一步执行的代码。主要指定服务器工作的端口以及回调函数。

2. fs.open()是用异步的方式打开一个文件。

选择两个示例很简单,因为libuv架构图可视:libuv对 Network I/O和 File I/O采用不同的机制。

上图右半部分,主要分成两个部分:

1. 主线程:主线程也是node启动时执行的现成。node启动时,会完成一系列的初始化动作,启动V8 engine,进入下一个循环。

2. 线程池:线程池的数量可以通过环境变量UV_THREADPOOL_SIZE配置,最大不超过128个,默认为4个。

Network I/O

V8 engine执行从server.listen() 开始,调用builtin module Tcp_wrap 的过程。

在创建TCP链接的过程中,libuv直接参与Tcp_wrap.cc函数中的 TCPWrap::listen() 调用uv_listen()开始到执行uv_io_start()结束。看起来很短暂的过程,其实是类似linux kernel的中断处理机制。

uv_io_start()负载将handle插入到处理的water queue中。这样的好处是请求能够立即得到处理。中断处理机制里面的下半部分与数据处理操作相似,交由主线程去完成处理。

代码逻辑很简单,查看loop中是否包含handle,如果有遍历default loop。

File I/O

这里我们研究一下 File I/O。

同Network I/O一样,我们的应用所依赖的fs模块,后面有一个builtin module Node_file.cc作为支撑。 Node_file.cc包含了各种我们常用的文件操作的接口,例如open, read, write, chmod,chown等。但同时,它们都支持异步模式。 我们通过Node_file.cc中的Open()函数来研究一下具体的实现细节。

如果你用类似source insight之类的代码阅读工具跟踪一下代码调用顺序,会很容易发现对于异步模式,Open()函数会在一系列辅助操作之后,进入函数uv_fs_open(),并且传入了一个FSReqWrap的对象。

FSReqWrap(),从名字可以看得出来,这是一个wrap,且是与FS相关的请求。也就是说,它基于某一个现成的机制来实现与FS相关的请求操作。这个现成的机制就是ReqWrap。好吧,它也是个wrap。乘你还没疯的时候,看一下图6吧。这里完整展示了FSReqWrap类继承关系。

除了FSReqWrap,还有其它Wrap,例如PipeConnectWrap,TCPConnectWrap等等。每个Wrap均为一种请求类型服务。 但是这些wrap,都是node自身的行为,而与libuv相关的是什么呢?上图中表示出了FSReqWrap关键的数据结构 uv_fs_s req__。

让我们把目光回到uv_fs_open()。在调用这个函数时, req__作为其一个重要的参数被传递进去。而在uv_fs_open()内部,req__则被添加到work queue的末尾中去。图3 thread pool中的thread会去领取这些request进行处理。 每个request很像一个粘贴板,它将event loop, work queue,每个请求的处理函数(work()),以及请求结束处理函数(done())绑定在一起。绑定的操作在uv__work_submit()中完成。 例如对于这里的req__,绑定在它身上的work()为uv__fs_work(), done()为uv__fs_done()。

这里有一个比较有意思的问题值得额外看一下。我们的thread pool是在什么时候建立的呢?

答案是:在第一次异步调用uv__work_submit()时。

每个thead的入口函数是 Threadpool.c中的worker()。工作逻辑比较简单,依次取出work queue中的请求,执行绑定在该请求上的work()函数。 前面我们提到的绑定在请求上的done()函数在哪里执行呢?这也是一个比较有意思的操作。libuv通过uv_async_send()通知event loop去执行相应的callback函数,也即我们绑定在request上的done()函数。uv__work_done()用于完成这样的操作。

uv_async_send()与主线程之间通过PIPE通信。

我在这一小节以一个FSReqWrap以及Open()函数为例,描述了libuv处理这种File I/O请求时所涉及的各种操作:

建立thread pool(只建立一次) 在每个请求req__上绑定与其相关的event loop, work queue, work(), done() thread worker()用来处理work queue里面的每个请求,并执行work() 通过uv_async_send()通知event loop执行done()

以上就是关于本次相关的知识点内容,感谢大家对脚本之家的支持。

相关文章

  • nodejs 的 session 简单使用

    nodejs 的 session 简单使用

    session 不用多介绍,使一个http可以对应一个终端用户,需要的朋友可以参考下。
    2016-06-06
  • 详解如何使用nvm管理Node.js多版本

    详解如何使用nvm管理Node.js多版本

    这篇文章主要介绍了详解如何使用nvm管理Node.js多版本,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-05-05
  • Node.JS中的模块、exports和module讲解

    Node.JS中的模块、exports和module讲解

    这篇文章主要介绍了Node.JS中的模块、exports和module讲解,模块分为两类一类是核心模块一类是文件模块,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • Node.js API详解之 Error模块用法实例分析

    Node.js API详解之 Error模块用法实例分析

    这篇文章主要介绍了Node.js API详解之 Error模块用法,结合实例形式分析了Node.js API中Error模块相关功能、函数、用法及操作注意事项,需要的朋友可以参考下
    2020-05-05
  • koa源码中promise的解读

    koa源码中promise的解读

    这篇文章主要介绍了koa源码中promise的解读,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • Node.js中处理错误的4种最佳方法分享

    Node.js中处理错误的4种最佳方法分享

    错误处理并不是编码工作中最吸引人的部分,但在 Node.js 中构建可靠、生产级别的应用程序时,它是绝对必要的,下面小编就来为大家介绍一下Node.js中处理错误的4种最佳方法吧
    2025-02-02
  • Node.js获取本机Mac地址的两种方案

    Node.js获取本机Mac地址的两种方案

    有时候我们的项目中可能会有日志记录的功能或者其他需要ip的功能,于是这时我们需要获取用户的ip地址或mac地址,下面这篇文章主要给大家介绍了关于Node.js获取本机Mac地址的两种方案,需要的朋友可以参考下
    2022-09-09
  • Nodejs使用express 编写接口的实现

    Nodejs使用express 编写接口的实现

    express是一个第三方模块,支持丰富的api,本文主要介绍了Nodejs使用express 编写接口的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-06-06
  • Node.js爬虫如何获取天气和每日问候详解

    Node.js爬虫如何获取天气和每日问候详解

    这篇文章主要给大家介绍了关于Node.js爬虫如何获取天气和每日问候的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Node.js爬虫具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • Node.js爬取豆瓣数据实例分析

    Node.js爬取豆瓣数据实例分析

    这篇文章通过实例给大家详细分析了Node.js爬取豆瓣数据的过程以及具体方法步骤,有兴趣的朋友可以参考学习下。
    2018-03-03

最新评论