这一系列文章主要分析nodejs中的核心库Libuv。
我的参考书:
朴灵的深入浅出nodejs
Jeffrey Richter的Windows核心编程
Anthony Williams的C++并发编程实战
reference.png
暂定为四篇:
1) 征服之初识篇(背景基础以及重要的概念,图示)
2) 征服之进展篇(libuv的编译,例子,内部用到的c语言技巧以及QUEUE的使用)
3) 征服之高潮篇(线程池,iocp,同步,并发,线程间的通信等)
4) 征服之和谐篇(Libuv的初始化,主循环,主线程和线程池之间的和谐交往)
通过征服Libuv系列文章,目的是让大家了解:
1) C语言之美(语法简单,功能强大,贴近硬件,适合系统级别编程,有很多技巧)
2) 多线程与线程的同步技术
3) 线程池技术
4) windows IOCP技术
5) 了解与ms PPL, intel TBB以及libdispatch(ios gcd)之间的异同点和优缺点。
6) vs c++中多线程下的debug技巧
之所以称为了解,而不是掌握,是因为这些技术偏向于底层的系统编程,并不是一撮而就的,需要一定的时间和经历才能沉淀下来的。因此只能说是让大家了解。
为了简单期间,一些限制条件:
仅关注windows下的实现
仅重点分析libuv的通用cpu密集型计算的框架,了解cpu密集计算框架,实际上异步io就比较容易理解了
因为windows下,异步io通过IOCP(完成端口),会使代码实现非常简单,而效率非常高。
在写此篇blog时,突然感觉到,是不是应该将libuv库进行拆分,将核心部分代码抽离出来单独运行,这样的好处就是要分析的代码量要少很多,仅关注我们感兴趣的代码,有利于演示。
还有一个目的:
就是在简化精华版的基础上升级一下,看看是否能够实现任务的动态均衡(ms PPL库和intel TBB库都有动态均衡,Work Stealing的功能,libuv目前确定没有此功能,libdispatch目前没发现,源码正在阅读中,还没看到)。这个实现难度还是很大的,就当练练手吧,哈哈
我尝试一下吧,看看是否可行!
1、背景:
前段时间,完成了一个微信项目,在后台选型过程中,花了将近一个月考察了java,php几个库,但最终却选择了nodejs,原因很简单:
1、java的配置实在是太麻烦了
2、php实在不熟悉,特别扭
3、nodejs使用js编程,我本人还是比较熟悉js的基础部分(不算es6.0 es7.0标准),并且npm真好用,实在是资源太丰富了,有时选择太多也是一种痛苦啊!
4、nodejs基于异步io技术,效率非常高。而且分布式部署简单。
通过无数次的比较,最终选定了令我非常满意的组合,感觉最起码少写了80%的代码。
后台配套方案:
framework: strongloop/loopback(被IBM收购了,只能说强大无比)
朴灵的: wechat / wechat-api / wechat-oauth
supersheep: wechat-pay
数据库: mongodb用于不需要事务处理的表 mysql用于支付的事务处理
因为没经验,在支付时需要事务处理,所以调整为使用mysql。不过从另外一个角度说明loopback的强大,支持多数据源的统一api操作。
前台配套方案:
总体而言,该前后台配套系统的开发非常令人愉悦。前台不好统计,但是微信后台,至少少写了80%代码!!
我正在做loopback方面的demo,来分享一下loopback框架和angularjs之间的互动,你会看到他们的配合是多么的默契。
近期会有blog以及demo提交github
2、演变:
目前基于异步回调的开发非常盛行,例如ios中的gcd,android中的基于接口回调方式。如果有过这些开发经验,你会觉得nodejs的异步事件开发模型还是蛮熟悉的。
随着逐渐熟悉nodejs,深深的喜欢上了nodejs,因此更想深入的了解一下nodejs是如何实现的。
通过了解nodejs的代码结构,结合深入浅出nodejs第三章的异步io所示流程图,逐步验证其正确性。特别是看到libuv中具有深厚c语言功底的老鸟所写的代码,忍不住想与大家分享c的代码之美!!
题外话:我深入研究过的或正在研究的以及即将研究的c源码库
随便说一下:现在c/c++貌似不太流行了。但是不管如何,c语言我认为是一门基础语言,每个程序员如果想要深入了解底层,最好学一下c语言。
我本人很喜欢c语言,曾经花了5年以上的时间自己研究3D游戏之父-约翰卡马克的quake系列引擎以及sgi opengl1.21实现(This is SGI's Sample Implementation of the OpenGL API. It is both a reference implementation and a driver framework used by **almost all commercial 3D hardware vendors **to develop hardware drivers for their systems)。
可以说quake引擎以及opengl源码是形成我科学程序观的基石,是技术源。(差点说成科学发展观了,这个太....)
目前正在阅读调试的c库源码:
libdispatch ios gcd中的函数都是来源于libdispatch,目前已经都移植到linux和windows中了
libuv 跨平台的异步io和work库
已编译并运行过demo,计划要阅读的c源码库:
libkqueue 一个跨平台的unix kqueue实现。实际在libdispatch移植到windows和linux版本时,就包含了libkqueue。因为libdispatch(源于macos和ios,他们都是基于unix系统的)基于kqueue实现。
libzmq跨平台的异步消息队列库(内部c++实现,以c api方式导出,很多库也使用这种方式)
zookeeper是一个分布式应用程序协调服务,是Hadoop和Hbase的重要组件。目前作为单独一个库独立出来了。
libuv目前基本了解整个流程了,其他几个等弄明白了,也一起分享吧,让我们一起来学c语言!
为什么选这些库:
1) 提高自身编程水平最好的方式是多阅读经典源码
2) 多线程,异步以及分布式、异步消息队列等都是目前主流,这些库是最高水平的实现,被大规模,广泛使用。
3) 这些库都是跨平台库,代码量不大,并且实用性又很高,功能单一,这就是c库的魅力所在。
4) 都是c语言实现,借助于ide的帮助,会很容易了解清楚整个流程。
3、libuv是什么?
libuv is a multi-platform support library with a focus on asynchronous I/O.
It was primarily developed for use by Node.js
由上面的介绍,我们可以知道:
1) 跨平台:windows linux unix都支持
2) 异步io:windows IOCP 、linux epoll、unix kqueue
3) 主要目的是用于nodejs,实际还有很多库或程序使用了libuv
例如目前风头正劲的跨平台.NetCore库(就是曾经大名鼎鼎的微软的asp.net)也是使用libuv作为核心
4) libuv不仅仅支持异步io操作,而且还具有一个强劲的线程池,用于支持多线程并行的cpu密集型操作。
这个才是我们重点要分析的模块
4、nodejs、google v8 javascript引擎和libuv之间的关系:
1) nodejs主要由google v8 javascript引擎和libuv组成
2) v8引擎绑定libuv实现的api,因此,既能使用ecma js标准语言来执行js代码,又能通过js调用libuv相关接口。
3) 由此可见,libuv本身是独立的c语言库,既可以直接使用c/c++来调用,也可以被绑定到c#(.NetCore)或者其他任何语言,例如java ,lua......
c/c++实现的库最大的好处就是能被各种其他编程语言所绑定和调用。
因为其他各种编程语言基本都是用c/c++来实现的,都留有接口与c/c++互调。
借用朴灵 深入浅出nodejs中的两张图来了解整个流程:
朴灵-深入浅出nodejs-架构图.png
朴灵-深入浅出nodejs-异步调用示意图.png
我们libuv源码分析以上图为指导,深入挖掘每个细节,验证其正确性,从而掌握整个libuv的精髓!
请将此图看上100遍,背出来,肯定有非常大帮助
nodejs就是数据通过v8引擎(主线程:数据输入)传递给Libuv进行处理(线程池:数据处理--根据数据类型不同,io数据由IOCP[windows]线程池处理,通用计算则由自己实现的线程池处理),libuv处理好后通知v8引擎我已经完成了,你来进行完成处理(主线程:完成回调,信息输出)。
其实从上面的叙述可以了解到以下几点:
1) v8 javascript引擎是单线程的,数据的输入,信息的输出(完成回调)都是在主线程中处理。这一点以后在源码分析中我们可以验证,通过vs强大的debug功能,我们可以很清晰的看到具体代码到底是运行在哪个线程中。
2) 但是数据处理模块(libuv)不是单线程的,它根据数据请求类型是否是io请求(socket,文件读写或管道等)还是work请求(非io请求)。不同的请求使用不同的处理策略。例如io请求,在windows下用IOCP,在linux下用epool。而work请求,windows和linux下都是使用统一的,自己实现的线程池。而我们的源码分析就是要证明上面的描述。
下一篇: 征服libuv之进展篇
.