nodejs调用rust的完整代码实例
作者:起个名字不容易啊
Rust主要用在一些需要高性能效果的地方,这篇文章主要介绍了nodejs调用rust的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
nodejs调用rust
调用rust的方式目前分为打包dll库调用和wasm
性能和跨平台兼容性分别有不同优缺点可根据各自需求
nodejs 调用rust的方式目前分为打包dll库调用和wasm
1. 调用 Rust 打包的 DLL 库
优点:
- 性能更高:DLL 是直接编译为本地机器代码的动态链接库,几乎没有额外的运行时开销。
- 直接访问系统资源:可以使用操作系统的底层功能,调用成本低。
- 适用于高性能需求:如果需要频繁调用复杂的计算逻辑,DLL 是更优的选择。
- 跨语言调用成熟:通过 Node.js 的
ffi-napi
或napi-rs
等库,可以高效与 Rust 的 DLL 交互。
缺点:
- 跨平台兼容性复杂:需要为 Windows(DLL)、macOS(.dylib)和 Linux(.so)分别构建对应的动态库。
- 部署复杂:需要在目标环境中正确配置动态库的路径。
- 线程安全性:如果你的 DLL 代码设计不当,可能导致线程冲突。
2. 调用 Rust 编译的 WASM
优点:
- 跨平台性:WASM 是平台无关的,运行时在所有支持 WebAssembly 的环境中都一致。
- 容易部署:Rust 编译为 WASM 后,生成一个
.wasm
文件,可以直接加载,不需要担心动态库路径。 - 安全性:WASM 在沙盒环境中运行,不直接访问底层资源,隔离更好。
缺点:
性能开销:
- WebAssembly 的沙盒环境导致运行时性能稍逊于本地代码。
- 如果需要频繁调用小粒度函数,调用开销可能显著。
与 Node.js 的绑定层次较浅:通过
@wasmer/wasi
或@wasm-tool/wasm-pack-plugin
等工具加载后,可能需要额外处理复杂的内存管理或数据交换问题。
性能比较
- 执行效率: DLL > WASM
DLL 是本地执行的动态链接库,几乎没有额外开销;WASM 有一定的沙盒化运行开销。 - 调用成本: DLL < WASM
调用 DLL 是直接的本地调用,而调用 WASM 涉及到序列化和反序列化。 - 部署复杂性: DLL > WASM
DLL 需要根据操作系统生成多个文件,WASM 只需一个文件即可运行。
如果你的 Rust 逻辑以高密度计算为主,例如数据处理、压缩等,推荐 DLL。如果是需要兼容多个环境,并且以一次性任务为主,推荐 WASM。
代码示例
- 先写点rust代码,并自动开启多线程处理数据
use rayon::prelude::*; #[no_mangle] pub extern "C" fn add_to_array(arr: *const i32, len: usize, num: i32, result: *mut i32) { let slice = unsafe { std::slice::from_raw_parts(arr, len) }; let output = unsafe { std::slice::from_raw_parts_mut(result, len) }; // 并行操作输出数组 output .par_iter_mut() .enumerate() .for_each(|(i, out)| { *out = slice[i] + num; }); }
Cargo.toml 文件
[package] name = "rust_napi" version = "0.1.0" edition = "2021" [dependencies] napi = { version = "2.11.0" } rand = "0.8" rayon = "1.7" [lib] crate-type = ["cdylib"] // mac 打包cdylib, windows 打包dll
如何将rust打包cdylib或者dll
// mac 指定架构 cargo build --release --target x86_64-apple-darwin // window cargo build --release
打包后会在当前目录生成target文件夹
x86_64-apple-darwin这个文件夹就是打包后生成的指定架构的包
- node 调用cdylib,并执行
node 调用cdylib需要使用到ffi-napi
// cargo build --release --target x86_64-apple-darwin const path = require("path"); const ffi = require("ffi-napi"); const ref = require("ref-napi"); // 动态确定库文件路径 "/rust_napi/target/x86_64-apple-darwin/release/librust_napi.dylib" const libName = process.platform === "win32" ? "librust_napi.dll" : process.platform === "darwin" ? "/rust_napi/target/x86_64-apple-darwin/release/librust_napi.dylib" : "librust_napi.so"; const libPath = path.join(__dirname, libName); // 加载 Rust 库 const rustLib = ffi.Library(libPath, { add_to_array: ["void", ["pointer", "size_t", "int", "pointer"]], }); function addToArray(arr, num) { const arrayLength = arr.length; const inputBuffer = Buffer.alloc(arrayLength * 4); // 每个 i32 占 4 字节 const outputBuffer = Buffer.alloc(arrayLength * 4); // 将 JavaScript 数组写入输入缓冲区 arr.forEach((value, index) => { inputBuffer.writeInt32LE(value, index * 4); }); // 调用 Rust 函数 rustLib.add_to_array(inputBuffer, arrayLength, num, outputBuffer); // 从输出缓冲区读取结果数组 const result = []; for (let i = 0; i < arrayLength; i++) { result.push(outputBuffer.readInt32LE(i * 4)); } return result; } const generateRandomIntArray = (size, min, max) => { return Array.from({ length: size }, () => Math.floor(Math.random() * (max - min) + min) ); }; let listy = generateRandomIntArray(4e7, 1, 100); let start = Date.now(); addToArray(listy, 100); console.log(Date.now() - start, 4); // rust 974 module.exports = { addToArray };
总结
到此这篇关于nodejs调用rust的文章就介绍到这了,更多相关nodejs调用rust内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!