使用rust链接node

258 阅读2分钟

node >=16

Express api

先用express 构建一个服务,用于我们测试

const express = require('express');
const {readdir , stat} = require("fs/promises");
const {join} = require("path");
const app = express();
const port = 3000;

const dirSize = async dir =>{
    const files = await readdir(dir,{withFileTypes:true})
    const paths = files.map( async file =>{
       const path = join(dir, file.name)
        if (file.isDirectory()) {
            return await dirSize(path)
        }
        if (file.isFile()){
            const {size } = await stat(path)
            return size
        }
       return 0
    })
    return (await Promise.all(paths)).flat(Infinity).reduce((i,size) => i+ size , 0)

}
app.get("/v1" , async (req,res)=>{
    console.time("dir")
    let size = await dirSize("./assets/")
    console.timeEnd('dir')
    res.json(size)
})

现在在assert文件夹下面大约有400个文件, 还有很多txt文件

启动服务后, curl -v http://127.0.0.1:3000/v1 测试一下, node大约需要68ms可以运行完成.

让我们来切换相同语法的Rust尝试

可以直接使用 Nodejs bindings 库来直接使用rust

先在Cargo.toml 里加载我们所需要的依赖项


[package]
name = "nodewith_rust"
version = "0.1.0"
edition = "2021"
[dependencies]
node-bindgen = {version = "5.0"}
[build-dependencies]
node-bindgen = {version = "5.0", features =["build"]}
[lib]
name = "nodewith_rust"
crate-type = ["cdylib"]

创建一个build.rs 文件

fn main (){
    node_bindgen::build::configure();
}

然后创建一个 src/lib.rs 文件, 用于做和node 相同的事情

use node_bindgen::derive::node_bindgen;
use std::{fs, io ,path::PathBuf};

fn get_size (path: impl Into<PathBuf>) -> io::Result<u64>{
   fn dir_size (mut dir: fs::ReadDir) -> io::Result<u64>{
        dir.try_fold(0 , |acc, file | {
            let file = file?;
            let size = match file.metadata()? {
                data if data.is_dir() => dir_size(fs::read_dir(file.path())?)?,
                data => data.len(),
            };
            Ok(acc+size )
        })

   }
    dir_size(fs::read_dir(path.into())?)
}
#[node_bindgen]
async fn size(path :String) -> u64 {
   if let Ok(dir_size) =   get_size(path){
       return dir_size;
   }
    else{
        return  0;
    }
}

现在要构建项目, 使用cargo install nj-cli 先运行 cargo build 然后运行 nj-cli build 会发现生成一个 dist/index.node 文件, 引用一下这个库来重新对比测试一下


const express = require('express');
const {readdir , stat} = require("fs/promises");
const {join} = require("path");
// 加载我们的rust module
const rustmodule = require("./dist/index")
const app = express();
const port = 3000;

const dirSize = async dir =>{
    const files = await readdir(dir,{withFileTypes:true})
    const paths = files.map( async file =>{
       const path = join(dir, file.name)
        if (file.isDirectory()) {
            return await dirSize(path)
        }
        if (file.isFile()){
            const {size } = await stat(path)
            return size
        }
       return 0
    })
    return (await Promise.all(paths)).flat(Infinity).reduce((i,size) => i+ size , 0)

}
app.get("/v1" , async (req,res)=>{
    console.time("dir")
    let size = await dirSize("./assets/")
    console.timeEnd('dir')
    res.json(size)
})
app.get("/v2", async (req,res) =>{
    console.time("dir")
    let size = await rustmodule.size("./assets/")
    console.timeEnd("dir")
    res.json({size:Number(size)})
})
app.listen(port, () => {
    console.log(`服务监听在${port}`)
})

启动服务, 在测试一下 curl -v http://127.0.0.1:3000/v2 会发现用rust写的库大约用了23ms提升了3倍左右

具体消耗时间取决于你的电脑性能

github地址 github.com/LuXinZ/rust…