node.jsnode-cluster

Why does sending a Date Object as a message from a worker thread convert it to a string?


I am trying to run some code across multiple CPUs. Each cpu is given some tasks and then they return the result to the main thread which aggregates everything together.

What I don't understand is that whenever I send a message containing a Date Object, that Date Object is converted to a string. It seems ridiculous to have to parse these to dates both in the worker threads and in the main thread. I am working with a lot of dates, so this will have a huge performance hit.

Is there anything I can do to get around this? I am using node version v10.13.0.

const cluster = require('cluster');

if (cluster.isMaster) {
  // init cluster
  require('os').cpus().forEach(() => {
    cluster.fork();
  });

  // add eventlisteners
  Object.values(cluster.workers).forEach(worker => {
    worker.on('message', message => {
      console.log(typeof message); // string
    });
  });
} else {
  process.send(new Date());
}

Solution

  • According to the 'message' event's documentation:

    The message goes through serialization and parsing.

    The serialization of a Date object is a string:

    // serialize and rebuilds an object: { test: "2019-03-05T16:20:17.863Z" }
    JSON.parse(JSON.stringify({test: new Date()}));
    

    So, no, there's no workaround: each process (workers and master alike) have its own environment (i.e. its own space to store objects), so you can't share references across different environments. To illustrate:

    const input = {some: 'thing'};
    const output = JSON.parse(JSON.stringify(input));
    console.log('are input and output the same object?', input === output); // false
    

    If you're concerned about performance on this, maybe rethink your architecture so that workers don't need to send that many dates over the channel.

    As a side note, you may have a boost in performance by using Date's internal timestamp instead of the default time string:

    const t0 = new Date();
    for (let i = 0; i < 1000000; i++) {
        const tmp = new Date();
        // this took ~6.9s on JSFiddle
        new Date(JSON.parse(JSON.stringify(tmp)));
        // this took ~2.8s on JSFiddle
        new Date(JSON.parse(JSON.stringify(+tmp)));
    }
    const t1 = new Date();
    console.log('time spent', t1 - t0);