C++ 方式
- npm install node-gyp -g
- mkdir demo && cd Demo && npm init
- 建立 fib.cc
- 建立binding.gyp
- node-gyp configure build
- 建立 測試 index.js 檔案
node-gyp https://github.com/nodejs/node-gyp
為了測試效能對比,演算法用了斐波那契的遞迴實現。 fib.cc:
// addon.cc
#include <node.h>
namespace demo {
using v8::Exception;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
unsigned int Fib_Recursive(unsigned int fib) {
if (fib > 2) {
return (Fib_Recursive(fib - 1) + Fib_Recursive(fib - 2));
}
else if (2 == fib) {
return 1;
}
else if (1 == fib) {
return 1;
}
return 1;
}
void Fib(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (!args[0]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "Wrong arguments")));
return;
}
int value = Fib_Recursive(args[0]->NumberValue());
Local<Number> num = Number::New(isolate, value);
args.GetReturnValue().Set(num);
}
void Init(Local<Object> exports) {
NODE_SET_METHOD(exports, "fib", Fib);
}
NODE_MODULE(Fib, Init)
} // namespace demo
複製程式碼
bing.gyp:
{
"targets": [
{
"target_name": "fib",
"sources": [ "fib.cc" ]
}
]
}
複製程式碼
nodejs 引用使用:
const Fib = require('./build/Release/fib');
// js
console.time('c++')
console.log(Fib.fib(40)); // 'world
console.timeEnd('c++')
function fib(n) {
if (n === 1 || n === 2) {
return 1
}
return fib(n - 1) + fib(n - 2)
}
function fib2(n) {
if (n < 2) {
return 1;
}
var a = 1, b = 1;
for (var i = 2; i < n - 1 ;i++ ) {
b = a + b;
a = b - a;
}
return a + b;
}
// js
console.time('node')
console.log(fib(40))
console.timeEnd('node')
console.log(process.memoryUsage());
複製程式碼
最後執行 node index.js 輸出
102334155
c++: 273.243ms
102334155
node: 1081.281ms
{ rss: 22708224,
heapTotal: 7159808,
heapUsed: 4478104,
external: 8236 }
複製程式碼
註釋掉c++程式碼再次執行 輸出:
node: 1037.292ms
{ rss: 22581248,
heapTotal: 7159808,
heapUsed: 4457040,
external: 8236 }
複製程式碼
這個主要看c++程式碼的記憶體使用情況: 4457040 - 4478104 = 20k。 整體效能提高很多,消耗記憶體較少。
基於Rust擴充套件
Rust語言特點: 優點:
- AOT編譯器
- 沒有垃圾收集器
- 記憶體安全預設
- 編譯的可執行檔案效能類似於C ++
- 具有依賴關係管理的包管理器
- Packages host
- 更好的社群
- 比C++寫起來容易
缺點:
- 入門曲線非常陡峭,足以讓很多人望而卻步
- 對程式設計意識要求較高,要能主動分辨去除可能會出現的同時讀寫的變數的情況,否則編譯不會通過
- 雖然官方的文件是中文的,但是官方的標準庫的文件是英文的
實現步驟:
- 安裝Rust:curl https://sh.rustup.rs -sSf | sh
- 安裝carco : $ curl -sSf https://static.rust-lang.org/rustup.sh | sh
- cargo new demo
- cd demo && npm init -y
- npm i ffi —save
- 在src/lib下 編寫lib.rs
- 設定 Cargo.toml 為crate-type = [“dylib”]
- cargo build --release
- 編寫測試index.js
lib.rs
#[no_mangle]
pub extern fn fib(n: i32) -> i32 {
return match n {
1 | 2 => 1,
n => fib(n - 1) + fib(n - 2)
}
}
複製程式碼
Cargo.toml
[package]
name = "cargo_test"
version = "0.1.0"
authors = ["zhangpeng53 <zhangpeng53@baidu.com>"]
[lib]
name = "ffi"
crate-type = ["dylib"]
複製程式碼
測試index.js
const ffi = require('ffi');
const rust = ffi.Library('target/release/libffi', {
fib: ['int', ['int']]
});
// rust
console.time('rust');
console.log(rust.fib(40));
console.timeEnd('rust');
function fib(n) {
if (n === 1 || n === 2) {
return 1
}
return fib(n - 1) + fib(n - 2)
}
function fib2(n) {
if (n < 2) {
return 1;
}
var a = 1, b = 1;
for (var i = 2; i < n - 1 ;i++ ) {
b = a + b;
a = b - a;
}
return a + b;
}
// js
console.time('node')
console.log(fib(40))
console.timeEnd('node')
console.log(process.memoryUsage());
複製程式碼
執行node index 輸出結果:
102334155
rust: 221.232ms
102334155
node: 1031.842ms
{ rss: 24068096,
heapTotal: 10330112,
heapUsed: 5375584,
external: 46765 }
複製程式碼
註釋rust程式碼輸出結果
102334155
node: 1051.661ms
{ rss: 22671360,
heapTotal: 7708672,
heapUsed: 4460048,
external: 8236 }
複製程式碼
rust 記憶體使用: 5375584 - 4460048 = 915k
總結:
兩者對比效能相似,rust使用記憶體較高,開發相對簡單。看你如何取捨了。