NodeJS Cluster:如何减少master中worker的数据?

时间:2017-11-19 13:56:08

标签: node.js multithreading process cluster-computing worker

我是nodejs的新手,我想要的是从数据库和计算中读取数据。为了加快速度,我使用了nodejs集群模块。

有两个全局变量:pairMap和nameSet,我在主进程中将作业分配给worker,并且他们做了一些计算工作(修改map和set,就像map-reduce一样)

然而,似乎对pairMap和nameSet没有修改并且为空。 (doMasterAction中的代码) (另一个奇怪的事情是我控制数据,它确实已经修改但最终在主进程中返回空)。

数据如下(我提取主要想法):

const Promise = require('bluebird');
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
const fs = Promise.promisifyAll(require('fs'))

const utils = {
    mergeMap:(source,dest)=>{
        for(let [key,value] of Object.entries(source)){
            if(!dest.has(key)) dest.set(key,value);
            for(let [type,arr] of Object.entries(value)){
                const final = new Set([...dest.get[key][type],...arr])
                dest.get[key][type] = final;
            }
        }
    }
}


/**
 * key: name1@group.com||name2@group.com
 * value: {to: [id1,id2,id3],cc,bcc}
 * @param row
 * @param map
 * @param nameSet
 */
function countLinks(res,map,nameSet) {
    nameSet.add(res);
    map.set(res,{ 'test': Math.floor(Math.random()*10+1)});
}


class hackingTeamPrepare {

    constructor(bulk=100000,total = 1150000){
        this.bulk = bulk;
        this.count = Math.ceil(total / this.bulk);
        const parallelArr = new Array(this.count).fill(0).map((v,i)=> i);
        this.jobs = parallelArr.map(v=> 'key'+v);
        this.pairMap = new Map();
        this.nameSet = new Set();

        this.bindThis();
    }

    bindThis(){
        this.doWorkerAction = this.doWorkerAction.bind(this);
        this.doMasterAction = this.doMasterAction.bind(this);
    }

    doMasterAction() {
        const workers = [],result = {};
        const self = this;
        let count = 0,timeout;

        for(let i=0;i<numCPUs;i++){
            const worker = cluster.fork();
            workers[i] = worker;
        }
        cluster.on('online', (worker) => {
            worker.send(self.jobs.shift());
        });
        cluster.on('exit', function() {
            if(self.jobs.length===0) return;
            console.log('A worker process died, restarting...');
        });

        cluster.on('message',function (senderWorkder,info) {
            const { workerId,jobIndex } = info;
            result[jobIndex] = true;
            console.log(`----worker ${workerId} done job: ${jobIndex}----`);

            const finish = !self.jobs.length && Object.keys(result).length===self.count;
            if(finish){
               // -----------------!!here!!--------------------------**
                console.log('-------finished-------',self.pairMap,self.nameSet); // Map {}, Set {}
                for(let id in cluster.workers){
                    const curWorker = cluster.workers[id];
                    curWorker.disconnect();
                }
            }else{
                if(!self.jobs.length) return;
                senderWorkder.send(self.jobs.shift());
            }
        })
    }



    /**
     * {[person1,person2]: {to,cc,bcc}}
     */
    doWorkerAction() {
        //Process为worker, receive from master
        const self = this;
        process.on('message',(sql)=>{
            const jobPromise = Promise.resolve(sql).then(res => {
                    countLinks(res,self.pairMap,self.nameSet);
                    const data = {
                        workerId: process.pid,
                        jobIndex: sql,
                    }

                    // send to master
                    process.send(data);
                }).catch(err=> {
                console.log('-----query error----',err)
            });
        })
    }

    readFromPG(){
        if(cluster.isMaster){
            this.doMasterAction();
        }else if (cluster.isWorker){
            this.doWorkerAction();
        }
    }

    init(){
        this.readFromPG();
    }
}

const test = new hackingTeamPrepare(2,10);
test.init();

任何人都可以帮助我吗?

我试图在主进程中手动合并数据,但是worker.send发送的数据似乎忽略了其中的对象。

1 个答案:

答案 0 :(得分:1)

在Node.js群集中,内存中的对象不在master和worker之间共享。

pairMapnameSet分别存在于主人和每个工人中。当一个worker修改这些对象时,它们会在同一个worker(进程)中发生变化,而在master和其他worker中保持不变。

为了使您的想法有效,您需要在主进程内部维护单个pairMap和单个nameSet,将包含您需要的任何数据的消息发送给工作者,并使用以下内容更新这些对象收到的数据。

请注意,您不能将任何对象作为消息从worker传递到master。如果您需要一些复杂的数据,则需要发送普通的javascript对象(键值对)。例如,如果您需要将Map实例从worker发送到master,请参阅从here获取的以下函数:

// source - http://2ality.com/2015/08/es6-map-json.html
function mapToJson(map) {
    return JSON.stringify([...map]);
}
function jsonToMap(jsonStr) {
    return new Map(JSON.parse(jsonStr));
}

// send message using this example:
process.send(mapToJson(pairMap));

// receive message:
worker.on('message', message => console.log(jsonToMap(message)))