Nodejs 原生 cluster 传递 function 对象
Nodejs 原生 cluster 传递 function 对象
最近写一个模拟器 希望用一个 master 动态分配任务给 worker
其他都好 就是在 master 中我写以下代码想发送个任务
cluster.workers[worker_id].send(message);
其中
message = {'type': 'new_job', 'content': bored};
可是在接收端收到的消息却没有 [function: bored]
message.content = undefined;
貌似 send() 直接无视了 function 对象
求破
p.s
我看传递 message 会用到 JSON 的 stringfy 是不是根本就不可能传递函数对象?
在 Node.js 中使用原生的 cluster
模块时,你可能会遇到一个问题:send()
方法不能直接传递函数对象。这是因为 send()
方法内部使用的是进程间的通信(IPC),而 IPC 只支持传递基本类型、Array 和 Buffer。
解释
send()
方法内部实际上使用了 JSON.stringify()
来序列化消息,而函数对象是无法被序列化的。因此,当你尝试将一个函数对象放入消息中时,它会被忽略或转换为 undefined
。
解决方案
如果你需要传递函数对象,可以考虑以下几种方法:
- 序列化函数:将函数字符串化,然后在接收端重新生成函数。
- 使用共享内存:如果需要频繁地传递函数对象,可以考虑使用
Worker_threads
模块来实现多线程通信,这样可以更灵活地处理复杂数据结构。
示例代码
1. 序列化函数
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
const worker = cluster.fork();
// 定义一个函数
function bored() {
console.log("Bored function called");
}
// 序列化函数
const funcStr = bored.toString();
// 发送消息
worker.send({ type: 'new_job', content: funcStr });
} else {
process.on('message', (msg) => {
if (msg.type === 'new_job') {
// 动态创建函数
new Function(msg.content)();
}
});
}
2. 使用 Worker_threads 模块
如果你的应用场景允许,可以考虑使用 Worker_threads
模块,它可以更灵活地处理复杂的对象。
// 主进程
const { Worker } = require('worker_threads');
if (cluster.isMaster) {
const worker = new Worker('./worker.js', { workerData: { func: bored.toString() } });
// 定义一个函数
function bored() {
console.log("Bored function called");
}
} else {
// 子进程
const { func } = workerData;
eval(func); // 重新定义函数
bored(); // 调用函数
}
总结
在 Node.js 的 cluster
模块中,由于 send()
方法的限制,直接传递函数对象是不可能的。你可以通过将函数转换为字符串并在另一端重新生成函数,或者使用 Worker_threads
模块来解决这个问题。
算了 直接 send
func.toString()
在 worker 那边重新组合成 function 了
在 Node.js 中使用原生 cluster
模块时,send()
方法确实不能直接传递函数对象。这是因为 send()
方法依赖于进程间的通信(IPC),而 IPC 机制只能传输基本数据类型和部分可序列化的对象(如 Array、Object 等),函数对象无法被序列化。
如果你需要将函数传递给 Worker 进程,可以考虑以下几种方法:
-
预先定义全局函数:如果 Worker 和 Master 需要执行相同的函数,可以在每个 Worker 进程中预先加载该函数。例如,可以在 Worker 启动时通过环境变量或配置文件来加载这些函数。
-
序列化函数:虽然不能直接传递函数对象,但你可以将函数转换为字符串形式,并通过某种方式(如序列化)传递给 Worker 进程。然后在 Worker 端反序列化并重新创建函数。这种方法较为复杂且性能较低。
-
通过消息传递函数名或标识符:你可以传递函数名或标识符,Worker 进程根据接收到的标识符调用相应的函数。这种方法依赖于预先定义好的函数映射。
以下是一个简单的示例,演示如何传递函数名称而不是函数本身:
Master 代码
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
const numWorkers = os.cpus().length;
for (let i = 0; i < numWorkers; i++) {
cluster.fork();
}
const workerId = 0;
const message = {
type: 'new_job',
content: 'bored',
funcName: 'handleJob'
};
cluster.workers[workerId].send(message);
} else {
process.on('message', (msg) => {
if (msg.type === 'new_job') {
handleJob(msg.content);
}
});
}
function handleJob(jobContent) {
console.log(`Worker ${process.pid} is handling job: ${jobContent}`);
}
在这个示例中,Master 发送了一个包含函数名称的消息给 Worker,Worker 根据函数名称调用相应的函数。这种方法避免了直接传递函数对象,而是传递函数名或标识符。