node 使用 node-gyp 做 c++ 拓展 比原生js 计算fib快了近三倍
参考
https://segmentfault.com/a/1190000023544791
由于bindings使用了node的fs等模块, 所以好像没办法在浏览器中使用…
安装依赖
yarn add node-gyp -g
yarn add bindings
yarn add node-addon-api
npm i -g node-gyp
npm i bindings -D
npm i node-addon-api -D
window10 会比较麻烦点, 需要安装vs, 我实在不想装那玩意,算了吧
npm install --global --production windows-build-tools@4.0.0
choco upgrade python2 visualstudio2017-workload-vctools
add.cc
#include <napi.h>
Napi::Value Add(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 2) {
Napi::TypeError::New(env, "Wrong number of arguments")
.ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber() || !info[1].IsNumber()) {
Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
return env.Null();
}
double arg0 = info[0].As<Napi::Number>().DoubleValue();
double arg1 = info[1].As<Napi::Number>().DoubleValue();
Napi::Number num = Napi::Number::New(env, arg0 + arg1);
return num;
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "add"), Napi::Function::New(env, Add));
return exports;
}
NODE_API_MODULE(add, Init)
binding.gyp
{
"targets": [
{
"target_name": "add",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [ "add.cc" ],
"include_dirs": [
"<!@(node -p "require("node-addon-api").include")"
],
"defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ],
}
]
}
add.js
const { add } = require("bindings")("add.node")
console.log(add(1, 2)) // 3
console.log(add(0.1, 0.2)) // 熟悉的 0.3XXXXX
构建运行
node-gyp configure
node-gyp build
fib.cc
#include <napi.h>
int fibCc(int n){
return n < 2 ? n : fibCc(n-1) + fibCc(n-2);
}
Napi::Value Fib(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
int n = info[0].As<Napi::Number>().Int32Value();
Napi::Number num = Napi::Number::New(env, fibCc(n));
return num;
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "fib"), Napi::Function::New(env, Fib));
return exports;
}
NODE_API_MODULE(fib, Init)
binding.gyp
{
"targets": [
{
"target_name": "fib",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [ "fib.cc" ],
"include_dirs": [
"<!@(node -p "require("node-addon-api").include")"
],
"defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ],
}
]
}
性能对比
居然快了近三倍???
const { fib } = require("bindings")("fib.node")
const fibJs = n => n < 2 ? n : fibJs(n - 1) + fibJs(n - 2)
for (let i = 0; i < 5; i++)
console.log(i, fib(i), fibJs(i))
const count = 40
const jsStart = +new Date()
for (let i = 0; i < count; i++)
fibJs(i)
const jsTime = +new Date() - jsStart
const ccStart = +new Date()
for (let i = 0; i < count; i++)
fib(i)
const ccTime = +new Date() - ccStart
console.log("js", jsTime)
console.log("cc", ccTime, ccTime / jsTime, jsTime / ccTime)