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 是不是根本就不可能传递函数对象?


3 回复

在 Node.js 中使用原生的 cluster 模块时,你可能会遇到一个问题:send() 方法不能直接传递函数对象。这是因为 send() 方法内部使用的是进程间的通信(IPC),而 IPC 只支持传递基本类型、Array 和 Buffer。

解释

send() 方法内部实际上使用了 JSON.stringify() 来序列化消息,而函数对象是无法被序列化的。因此,当你尝试将一个函数对象放入消息中时,它会被忽略或转换为 undefined

解决方案

如果你需要传递函数对象,可以考虑以下几种方法:

  1. 序列化函数:将函数字符串化,然后在接收端重新生成函数。
  2. 使用共享内存:如果需要频繁地传递函数对象,可以考虑使用 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 进程,可以考虑以下几种方法:

  1. 预先定义全局函数:如果 Worker 和 Master 需要执行相同的函数,可以在每个 Worker 进程中预先加载该函数。例如,可以在 Worker 启动时通过环境变量或配置文件来加载这些函数。

  2. 序列化函数:虽然不能直接传递函数对象,但你可以将函数转换为字符串形式,并通过某种方式(如序列化)传递给 Worker 进程。然后在 Worker 端反序列化并重新创建函数。这种方法较为复杂且性能较低。

  3. 通过消息传递函数名或标识符:你可以传递函数名或标识符,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 根据函数名称调用相应的函数。这种方法避免了直接传递函数对象,而是传递函数名或标识符。

回到顶部