what

打算好好学习一下 nodejs,那就先从 nodejs 官方文档看起吧,这篇博客主要是记录一下 nodejs 下的 c++ addons 模块,看 nodejs 为什么要引入 c++ ,以及如何引入 c++ 代码。

c++ addons 官方文档

why

nodejs 采用事件驱动、异步编程,为网络服务而设计。其实 Javascript 的匿名函数和闭包特性非常适合事件驱动、异步编程。非阻塞模式的 IO 处理给 Node.js 带来在相对低系统资源耗用下的高性能与出众的负载能力,非常适合用作依赖其它 IO 资源的中间层服务。

Nodejs 虽然有着不错的异步能力,但是在密集型计算的时候却并不出众,简单来说所有的异步任务会维护在一个事件循环中(队列),线程会不断的去事件循环中取任务来执行,当 CPU 密集型的任务造成执行时间过长,就会导致其他任务无法执行,这样整个程序的性能就不行了。这个时候就可以用 c++ 来编写一些 nodejs 模块,加快运算时间。

how

以 fibonacci 函数为例,先看一下运行结果。

var fibonacciC = require("./build/Release/fibonacci.node").fibonacci;
function fibonacciJS(n) {
  if (n <= 0) return 0;
  else if (n == 1) return 1;
  else return fibonacciJS(n - 1) + fibonacciJS(n - 2);
}

console.time("c++");
console.log(fibonacciC(40));
console.timeEnd("c++");

console.time("js");
console.log(fibonacciJS(40));
console.timeEnd("js");

// 输出
102334155
c++: 524.515ms
102334155
js: 1.335s

在 40 次的递归运算中,可以看到采用原生 js 实现的方式,时间是 c++ 方式实现的两倍多,如果计算时间更长的话,原生 js 实现的效率更低。

接下来看一下是如何把 c++ 的代码结合到 nodejs 中。

编写 c++ 代码

// fibonacci.cc
#include <node.h>

using namespace std;

namespace demo {

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Number;
using v8::Value;

int fib(int n) {
   if (n <= 0)
        return 0;
    else if (n == 1)
        return 1;
    else
        return fib(n - 1) + fib(n - 2);
}

/* 通过 FunctionCallbackInfo<Value>& args 可以设置返回值 */
void fibonacci(const FunctionCallbackInfo<Value>& args) {
  Isolate *isolate = args.GetIsolate();
  // node v10 版本之前是这样获取 number 参数的
  // args[0]->NumberValue()
  // v10 版本之后是这样获取的
  // args[0].As<Number>()->Value()
  Local<Number> num = Number::New(isolate, fib(args[0].As<Number>()->Value()));

  // 设置函数调用的返回值
  args.GetReturnValue().Set(num);
  return ;
}

void Initialize(Local<Object> exports) {
  // 指定 module 名字
  NODE_SET_METHOD(exports, "fibonacci", fibonacci);
}

// 加载 module
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

}

编译 c++ 代码

# 首先要安装 node-gyp
npm i -g node-gyp

在当前目录下添加 binding.gyp 文件,内容为:

{
  "targets": [
    {
      "target_name": "fibonacci",
      "sources": [ "fibonacci.cc" ]
    }
  ]
}

运行打包编译命令

# 先打包
node-gyp  configure
# 会生成一个 build 目录,然后进入这个目录
cd build
# 编译文件
make

这个时候会生成一个 build 目录,以及 build 目录下的 Release 目录。

引入 c++ 模块

接下来就可以像这样引入该模块

var fibonacciC = require("./build/Release/fibonacci.node").fibonacci;
console.log(fibonacciC(40));

总结

引入 c++ ,借助其高效的计算能力,可以让 nodejs 也进行一些密集型的计算,本文只是一个简单的实例,更多强大的功能还需要看官方文档以及熟悉 c++ 才行。


作者: Kavience 本文链接: http://www.kavience.com/frontend/getting-started-with-nodejs-module-addons.html 转载请注明:《Nodejs模块addons入门》转自 http://www.kavience.com/frontend/getting-started-with-nodejs-module-addons.html,原作者:Kavience 版权声明: 自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)