#nodejs #worker #process #js #pool

node-workers

一组长生存期的 nodejs 工作进程

6 个版本 (3 个破坏性更新)

0.8.0 2022年4月18日
0.7.0 2022年4月15日
0.6.0 2022年4月12日
0.5.2 2022年4月11日

#652 in 并发

MIT 许可证

37KB
720

Rust Node Workers

CI crates.io documentation

这允许您使用工作进程池从 Rust 代码调用 node 二进制文件。这对于大多数代码用 Rust 编写但需要利用 Node 包执行某些任务(如使用 TypeScript 的 API 或使用 JS 框架进行 SSR)的项目很有用。
使用工作进程池是避免在多次调用中启动 node 二进制文件成本的基本方法。中等或大型 Node 二进制文件可能需要约一秒(或更长时间)来启动(或更多),使用一组长生存期进程可以在后续运行中节省您的时间。如果在您的程序使用过程中需要多次与 node 二进制文件交互,可重用和长生存期进程将为您节省大量时间。

此解决方案与在 Node 中调用 rust(如使用 napi-rs 等解决方案)的方式不同。如果您的代码大部分是用 Rust 编写的,那么创建和维护 node 插件的额外开销将不值得。

该池会启动一个长生存期 node 进程,并通过 stdin/stdout 与其通信,这使得此解决方案跨平台。
要与其通信,node-workers 提供了一个桥接器,需要在创建要与之交互的 node 二进制文件时使用。

// worker.js
const { bridge } = require('rust-node-workers');

bridge({
  ping: (payload) => {
    console.log(`pong at ${new Date()}`);
    return payload * 2;
  }
});

然后,您可以从 Rust 代码分配任务给这个工作进程

use node_workers::{WorkerPool};

let mut pool = WorkerPool::setup("worker", 4); // 4 max workers
let result = pool.perform::<u32, _>("ping", vec![100]).unwrap();
println!("result: {:?}", result);

安装

需要安装 npm 包来设置桥接器

yarn add rust-node-workers

在您的 rust 项目中

[dependencies]
node-workers = "0.8.0"

用法

此 crate 暴露了一个 WorkerPool,您可以用池的长度实例化它。当需要执行任务时,如果需要,将创建一个新的工作进程,直到达到最大数量。

let pool = WorkerPool::setup("examples/worker", 4); // 4 max workers

然后,您可以使用 run_workerperform 从您的工人调用任务。

run_worker 在新线程上的工作进程中执行任务。在线程上使用 get_result 将等待工作进程完成并反序列化结果(如果有)。

let mut pool = WorkerPool::setup("examples/worker", 2);
pool.run_worker("fib", 80u32); // on a separate thread

let thread = pool.run_worker("fib2", 40u32);
// join the thread's handle
let result = thread.get_result::<u32>().unwrap();
println!("run_worker result: {:?}", result);

perform 接收要处理的数据数组,并为每个值运行一个工作进程。

let files = /* vector of TypeScript files */;
// execute the command "getInterfaces" on every file
// each executed worker will return an array of interfaces (Vec<Interface>)
let interfaces = pool
  .perform::<Vec<Interface>, _>("getInterfaces", files)
  .unwrap();

// it may be benefic to send multiple files to each worker instead of just one
let file_chunks = files.chunks(30);
let interfaces = pool
  .perform::<Vec<Interface>, _>("getInterfacesBulk", file_chunks)
  .unwrap();

对于不需要任何有效负载的任务,可以使用 EmptyPayload

pool.run_worker("ping", EmptyPayload::new());

有关其他用法,请参阅文档以及存储库中的示例

开发

构建

yarn build

运行示例

cargo run --example

发布

  • 版本-请更新
  • 调整 package.json 版本
  • git提交 -m "chore: 发布" && gittag vx.y.z && git推送 --跟踪标签
  • npm发布--访问=公开

依赖项

~0.8–1.5MB
~34K SLoC