js-shm: 高性能 Node.js 共享内存模块
什么是 js-shm
js-shm 是一个基于 Linux 共享内存机制实现的高性能 Node.js 模块,使用 node-addon-api 作为 C++ 接口层,为 Node.js 提供接近原生速度的跨进程通信能力。
核心特点
极致性能
- 写入吞吐量:60+ GB/s(64KB 数据)
- 读取吞吐量:60+ GB/s(复用 Buffer)
- 往返延迟:< 10 μs(64KB 数据)
线程安全
- 使用 POSIX 信号量(Semaphore)保护共享内存操作
- 支持多进程并发读写,无数据竞争
- 服务端/客户端模式,正确处理资源生命周期
实时通知
- 后台轮询线程检测数据变化
- 使用
ThreadSafeFunction安全回调 JavaScript - 事件延迟 < 500 μs
技术架构
#mermaid-svg-95S4xYkd6WjhFDyt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-95S4xYkd6WjhFDyt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-95S4xYkd6WjhFDyt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-95S4xYkd6WjhFDyt .error-icon{fill:#552222;}#mermaid-svg-95S4xYkd6WjhFDyt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-95S4xYkd6WjhFDyt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-95S4xYkd6WjhFDyt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-95S4xYkd6WjhFDyt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-95S4xYkd6WjhFDyt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-95S4xYkd6WjhFDyt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-95S4xYkd6WjhFDyt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-95S4xYkd6WjhFDyt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-95S4xYkd6WjhFDyt .marker.cross{stroke:#333333;}#mermaid-svg-95S4xYkd6WjhFDyt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-95S4xYkd6WjhFDyt p{margin:0;}#mermaid-svg-95S4xYkd6WjhFDyt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-95S4xYkd6WjhFDyt .cluster-label text{fill:#333;}#mermaid-svg-95S4xYkd6WjhFDyt .cluster-label span{color:#333;}#mermaid-svg-95S4xYkd6WjhFDyt .cluster-label span p{background-color:transparent;}#mermaid-svg-95S4xYkd6WjhFDyt .label text,#mermaid-svg-95S4xYkd6WjhFDyt span{fill:#333;color:#333;}#mermaid-svg-95S4xYkd6WjhFDyt .node rect,#mermaid-svg-95S4xYkd6WjhFDyt .node circle,#mermaid-svg-95S4xYkd6WjhFDyt .node ellipse,#mermaid-svg-95S4xYkd6WjhFDyt .node polygon,#mermaid-svg-95S4xYkd6WjhFDyt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-95S4xYkd6WjhFDyt .rough-node .label text,#mermaid-svg-95S4xYkd6WjhFDyt .node .label text,#mermaid-svg-95S4xYkd6WjhFDyt .image-shape .label,#mermaid-svg-95S4xYkd6WjhFDyt .icon-shape .label{text-anchor:middle;}#mermaid-svg-95S4xYkd6WjhFDyt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-95S4xYkd6WjhFDyt .rough-node .label,#mermaid-svg-95S4xYkd6WjhFDyt .node .label,#mermaid-svg-95S4xYkd6WjhFDyt .image-shape .label,#mermaid-svg-95S4xYkd6WjhFDyt .icon-shape .label{text-align:center;}#mermaid-svg-95S4xYkd6WjhFDyt .node.clickable{cursor:pointer;}#mermaid-svg-95S4xYkd6WjhFDyt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-95S4xYkd6WjhFDyt .arrowheadPath{fill:#333333;}#mermaid-svg-95S4xYkd6WjhFDyt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-95S4xYkd6WjhFDyt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-95S4xYkd6WjhFDyt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-95S4xYkd6WjhFDyt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-95S4xYkd6WjhFDyt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-95S4xYkd6WjhFDyt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-95S4xYkd6WjhFDyt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-95S4xYkd6WjhFDyt .cluster text{fill:#333;}#mermaid-svg-95S4xYkd6WjhFDyt .cluster span{color:#333;}#mermaid-svg-95S4xYkd6WjhFDyt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-95S4xYkd6WjhFDyt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-95S4xYkd6WjhFDyt rect.text{fill:none;stroke-width:0;}#mermaid-svg-95S4xYkd6WjhFDyt .icon-shape,#mermaid-svg-95S4xYkd6WjhFDyt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-95S4xYkd6WjhFDyt .icon-shape p,#mermaid-svg-95S4xYkd6WjhFDyt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-95S4xYkd6WjhFDyt .icon-shape .label rect,#mermaid-svg-95S4xYkd6WjhFDyt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-95S4xYkd6WjhFDyt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-95S4xYkd6WjhFDyt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-95S4xYkd6WjhFDyt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Linux 内核
C++ 层
Node.js 进程
用户代码
JavaScript API
write/read/onData
SharedMemWrap
node-addon-api
sharedMem
send/recv
dev/shm 共享内存
SharedMemHeader
seq_count
data_len
data
POSIX Semaphore
信号量 共享内存 进程 B (消费者) 进程 A (生产者) 信号量 共享内存 进程 B (消费者) 进程 A (生产者) #mermaid-svg-UufNuNX0hvxUSwy2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UufNuNX0hvxUSwy2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UufNuNX0hvxUSwy2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UufNuNX0hvxUSwy2 .error-icon{fill:#552222;}#mermaid-svg-UufNuNX0hvxUSwy2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UufNuNX0hvxUSwy2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UufNuNX0hvxUSwy2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UufNuNX0hvxUSwy2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UufNuNX0hvxUSwy2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UufNuNX0hvxUSwy2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UufNuNX0hvxUSwy2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UufNuNX0hvxUSwy2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UufNuNX0hvxUSwy2 .marker.cross{stroke:#333333;}#mermaid-svg-UufNuNX0hvxUSwy2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UufNuNX0hvxUSwy2 p{margin:0;}#mermaid-svg-UufNuNX0hvxUSwy2 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UufNuNX0hvxUSwy2 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-UufNuNX0hvxUSwy2 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UufNuNX0hvxUSwy2 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-UufNuNX0hvxUSwy2 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-UufNuNX0hvxUSwy2 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-UufNuNX0hvxUSwy2 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-UufNuNX0hvxUSwy2 .sequenceNumber{fill:white;}#mermaid-svg-UufNuNX0hvxUSwy2 #sequencenumber{fill:#333;}#mermaid-svg-UufNuNX0hvxUSwy2 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-UufNuNX0hvxUSwy2 .messageText{fill:#333;stroke:none;}#mermaid-svg-UufNuNX0hvxUSwy2 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UufNuNX0hvxUSwy2 .labelText,#mermaid-svg-UufNuNX0hvxUSwy2 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-UufNuNX0hvxUSwy2 .loopText,#mermaid-svg-UufNuNX0hvxUSwy2 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-UufNuNX0hvxUSwy2 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UufNuNX0hvxUSwy2 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-UufNuNX0hvxUSwy2 .noteText,#mermaid-svg-UufNuNX0hvxUSwy2 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-UufNuNX0hvxUSwy2 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UufNuNX0hvxUSwy2 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UufNuNX0hvxUSwy2 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UufNuNX0hvxUSwy2 .actorPopupMenu{position:absolute;}#mermaid-svg-UufNuNX0hvxUSwy2 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-UufNuNX0hvxUSwy2 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UufNuNX0hvxUSwy2 .actor-man circle,#mermaid-svg-UufNuNX0hvxUSwy2 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-UufNuNX0hvxUSwy2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 获取锁 锁定成功 write(data) 更新 seq_count 更新 data_len memcpy 数据 释放锁 解锁 获取锁 锁定成功 read(buffer) memcpy 到 buffer 释放锁 解锁
#mermaid-svg-8xZfrbPx4EfjSza8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8xZfrbPx4EfjSza8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8xZfrbPx4EfjSza8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8xZfrbPx4EfjSza8 .error-icon{fill:#552222;}#mermaid-svg-8xZfrbPx4EfjSza8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8xZfrbPx4EfjSza8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8xZfrbPx4EfjSza8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8xZfrbPx4EfjSza8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8xZfrbPx4EfjSza8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8xZfrbPx4EfjSza8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8xZfrbPx4EfjSza8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8xZfrbPx4EfjSza8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8xZfrbPx4EfjSza8 .marker.cross{stroke:#333333;}#mermaid-svg-8xZfrbPx4EfjSza8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8xZfrbPx4EfjSza8 p{margin:0;}#mermaid-svg-8xZfrbPx4EfjSza8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8xZfrbPx4EfjSza8 .cluster-label text{fill:#333;}#mermaid-svg-8xZfrbPx4EfjSza8 .cluster-label span{color:#333;}#mermaid-svg-8xZfrbPx4EfjSza8 .cluster-label span p{background-color:transparent;}#mermaid-svg-8xZfrbPx4EfjSza8 .label text,#mermaid-svg-8xZfrbPx4EfjSza8 span{fill:#333;color:#333;}#mermaid-svg-8xZfrbPx4EfjSza8 .node rect,#mermaid-svg-8xZfrbPx4EfjSza8 .node circle,#mermaid-svg-8xZfrbPx4EfjSza8 .node ellipse,#mermaid-svg-8xZfrbPx4EfjSza8 .node polygon,#mermaid-svg-8xZfrbPx4EfjSza8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8xZfrbPx4EfjSza8 .rough-node .label text,#mermaid-svg-8xZfrbPx4EfjSza8 .node .label text,#mermaid-svg-8xZfrbPx4EfjSza8 .image-shape .label,#mermaid-svg-8xZfrbPx4EfjSza8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-8xZfrbPx4EfjSza8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8xZfrbPx4EfjSza8 .rough-node .label,#mermaid-svg-8xZfrbPx4EfjSza8 .node .label,#mermaid-svg-8xZfrbPx4EfjSza8 .image-shape .label,#mermaid-svg-8xZfrbPx4EfjSza8 .icon-shape .label{text-align:center;}#mermaid-svg-8xZfrbPx4EfjSza8 .node.clickable{cursor:pointer;}#mermaid-svg-8xZfrbPx4EfjSza8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8xZfrbPx4EfjSza8 .arrowheadPath{fill:#333333;}#mermaid-svg-8xZfrbPx4EfjSza8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8xZfrbPx4EfjSza8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8xZfrbPx4EfjSza8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8xZfrbPx4EfjSza8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8xZfrbPx4EfjSza8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8xZfrbPx4EfjSza8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8xZfrbPx4EfjSza8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8xZfrbPx4EfjSza8 .cluster text{fill:#333;}#mermaid-svg-8xZfrbPx4EfjSza8 .cluster span{color:#333;}#mermaid-svg-8xZfrbPx4EfjSza8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8xZfrbPx4EfjSza8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8xZfrbPx4EfjSza8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-8xZfrbPx4EfjSza8 .icon-shape,#mermaid-svg-8xZfrbPx4EfjSza8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8xZfrbPx4EfjSza8 .icon-shape p,#mermaid-svg-8xZfrbPx4EfjSza8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8xZfrbPx4EfjSza8 .icon-shape .label rect,#mermaid-svg-8xZfrbPx4EfjSza8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8xZfrbPx4EfjSza8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8xZfrbPx4EfjSza8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8xZfrbPx4EfjSza8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 内存布局
seq_count
uint64_t
data_len
uint64_t
data
uint8_t\[\]
性能对比
| 操作 | 数据大小 | 吞吐量 |
|---|---|---|
| 写入 | 64KB | 60+ GB/s |
| 读取(复用 Buffer) | 64KB | 60+ GB/s |
| 读取(每次分配) | 64KB | ~2 GB/s |
| 往返延迟 | 64KB | < 10 μs |
使用场景
1. 多进程数据共享
javascript
// 进程 A - 生产者
const { SharedMem } = require('./index');
const mem = new SharedMem('my_shared_data', 1024 * 1024, true);
setInterval(() => {
const data = Buffer.from(JSON.stringify({ timestamp: Date.now() }));
mem.write(data);
}, 100);
javascript
// 进程 B - 消费者
const { SharedMem } = require('./index');
const mem = new SharedMem('my_shared_data', 1024 * 1024, false);
const buf = Buffer.alloc(1024 * 1024);
setInterval(() => {
const len = mem.read(buf);
const data = buf.slice(0, len);
console.log(JSON.parse(data.toString()));
}, 100);
2. 事件驱动通信
javascript
const { SharedMem } = require('./index');
const mem = new SharedMem('event_channel', 65536, true);
mem.onData((data) => {
console.log('收到数据:', data.length, 'bytes');
});
mem.write(Buffer.from('Hello from js-shm!'));
3. 高性能数据管道
javascript
const { SharedMem } = require('./index');
const mem = new SharedMem('data_pipeline', 1024 * 1024, true);
const readBuf = Buffer.alloc(1024 * 1024);
// 写入性能测试
const data = Buffer.alloc(65536, 'x');
const start = process.hrtime.bigint();
for (let i = 0; i < 10000; i++) {
mem.write(data);
}
const end = process.hrtime.bigint();
const timeMs = Number(end - start) / 1000000;
console.log(`写入 625MB 耗时: ${timeMs.toFixed(2)}ms`);
安装与使用
bash
# 安装依赖
npm install
# 编译 C++ 扩展
npm run build
# 运行测试
npm test
# 运行性能测试
npm run test:perf
项目结构
js-shm/
├── binding.gyp # node-gyp 配置
├── package.json # npm 配置
├── index.js # JavaScript 接口
├── plugs.cpp # Node.js 插件入口
├── sharedMemWrap.hpp # C++ 封装头文件
├── sharedMemWrap.cpp # C++ 封装实现
├── test.js # 单元测试
├── test_perf.js # 性能测试
└── README.md # 项目文档
性能测试结果
=== 性能测试开始 ===
1. 写入吞吐量测试
--- 写入吞吐量测试 ---
数据大小: 64 B, 迭代: 10000, 总数据: 625.00 KB
耗时: 1.97 ms, 吞吐量: 309.45 MB/s
数据大小: 64.00 KB, 迭代: 10000, 总数据: 625.00 MB
耗时: 10.72 ms, 吞吐量: 58307.20 MB/s
2. 读取吞吐量测试
--- 读取吞吐量测试 (复用Buffer) ---
数据大小: 64.00 KB, 迭代: 10000, 总数据: 625.00 MB
耗时: 10.23 ms, 吞吐量: 61084.96 MB/s
3. 往返延迟测试
--- 往返延迟测试 ---
数据大小: 64 B, 迭代: 10000
平均延迟: 1.04 μs
为什么选择 js-shm
vs Redis
- 无需网络开销,直接内存访问
- 延迟降低 99%(从 ms 级降至 μs 级)
- 无需部署额外服务
vs IPC / Socket
- 共享内存是最快的进程间通信方式
- 吞吐量提升 100x
- 零拷贝数据传输
vs Node.js 原生 cluster
- 真正的跨进程共享,不限于父子进程
- 支持任意数量进程同时访问
- 独立于 Node.js 运行时
技术细节
内存布局
cpp
struct SharedMemHeader {
uint64_t seq_count; // 序列号,用于检测数据变化
uint64_t data_len; // 实际数据长度
uint8_t data[0]; // 柔性数组,存储实际数据
};
线程安全机制
cpp
class semaphore {
public:
void lock() { sem_wait(p_sem__); }
void unlock() { sem_post(p_sem__); }
};
size_t send(const uint8_t* data, size_t len) {
smfLockGuard lck(m_smf__); // RAII 自动加锁
// 写入数据...
}
Node.js 回调机制
cpp
napi_status status = m_tsfn__.NonBlockingCall(data, [](Napi::Env env, Napi::Function jsCallback, uint8_t* data) {
Napi::Buffer<uint8_t> buffer = Napi::Buffer<uint8_t>::New(env, data, len);
jsCallback.Call({buffer});
});
总结
js-shm 为 Node.js 提供了一个高性能、线程安全、易于使用的共享内存解决方案。无论是多进程数据共享、实时事件通信还是高性能数据管道,js-shm 都能满足您的需求。