热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Nodejslibuv运行原理详解

在本篇文章里小编给大家整理的是关于Nodejslibuv运行原理以及相关知识点,有需要的朋友们可以学习下。

前言

这应该是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()

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


推荐阅读
  • 如何高效学习鸿蒙操作系统:开发者指南
    本文探讨了开发者如何更有效地学习鸿蒙操作系统,提供了来自行业专家的建议,包括系统化学习方法、职业规划建议以及具体的开发技巧。 ... [详细]
  • 本文详细探讨了如何根据不同的应用场景选择合适的PHP版本,包括多版本切换技巧、稳定性分析及针对WordPress等特定平台的版本建议。 ... [详细]
  • 实现Win10与Linux服务器的SSH无密码登录
    本文介绍了如何在Windows 10环境下使用Git工具,通过配置SSH密钥对,实现与Linux服务器的无密码登录。主要步骤包括生成本地公钥、上传至服务器以及配置服务器端的信任关系。 ... [详细]
  • 本文探讨了服务器系统架构的性能评估方法,包括性能评估的目的、步骤以及如何选择合适的度量标准。文章还介绍了几种常用的基准测试程序及其应用,并详细说明了Web服务器性能评估的关键指标与测试方法。 ... [详细]
  • WebBenchmark:强大的Web API性能测试工具
    本文介绍了一款名为WebBenchmark的Web API性能测试工具,该工具不仅支持HTTP和HTTPS服务的测试,还提供了丰富的功能来帮助开发者进行高效的性能评估。 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • 随着Linux操作系统的广泛使用,确保用户账户及系统安全变得尤为重要。用户密码的复杂性直接关系到系统的整体安全性。本文将详细介绍如何在CentOS服务器上自定义密码规则,以增强系统的安全性。 ... [详细]
  • Java中提取字符串的最后一部分
    本文介绍了如何使用Java中的substring()和split()方法来提取字符串的最后一部分,特别是在处理包含特殊字符的路径时的方法与技巧。 ... [详细]
  • Java虚拟机及其发展历程
    Java虚拟机(JVM)是每个Java开发者日常工作中不可或缺的一部分,但其背后的运作机制却往往显得神秘莫测。本文将探讨Java及其虚拟机的发展历程,帮助读者深入了解这一关键技术。 ... [详细]
  • 本文基于Java官方文档进行了适当修改,旨在介绍如何实现一个能够同时处理多个客户端请求的服务端程序。在前文中,我们探讨了单客户端访问的服务端实现,而本篇将深入讲解多客户端环境下的服务端设计与实现。 ... [详细]
  • 服务器虚拟化存储设计,完美规划储存与资源,部署高性能虚拟化桌面
    规划部署虚拟桌面环境前,必须先估算目前所使用实体桌面环境的工作负载与IOPS性能,并慎选储存设备。唯有谨慎估算贴近实际的IOPS性能,才能 ... [详细]
  • 本文介绍了如何使用Node.js通过两种不同的方法连接MongoDB数据库,包括使用MongoClient对象和连接字符串的方法。每种方法都有其特点和适用场景,适合不同需求的开发者。 ... [详细]
  • 本文详细介绍如何安装和配置DedeCMS的移动端站点,包括新版本安装、老版本升级、模板适配以及必要的代码修改,以确保移动站点的正常运行。 ... [详细]
  • Asynchronous JavaScript and XML (AJAX) 的流行很大程度上得益于 Google 在其产品如 Google Suggest 和 Google Maps 中的应用。本文将深入探讨 AJAX 在 .NET 环境下的工作原理及其实现方法。 ... [详细]
  • JavaScript 跨域解决方案详解
    本文详细介绍了JavaScript在不同域之间进行数据传输或通信的技术,包括使用JSONP、修改document.domain、利用window.name以及HTML5的postMessage方法等跨域解决方案。 ... [详细]
author-avatar
袁怡松_779
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有