3

The communication between my main thread and the webworker was really slow, so I took a look at this question which told me to how to use buffers to make the communication speed almost seemingless.

An answer to that question has communication of 0.4ms for an array containing 90000000 elements of the same kind as in my example.

The code is evaluating genomes in a neuroevolution algorithm set up with Neataptic to see how well their performing on the MNIST dataset, but it shouldn't be part of the problem.

I simply have an array with just 397000 elements, and the communication time varies between 30 and 50ms. This is a JSFiddle of my code (open console) - also below here:

/** Rename vars */
var Neat    = neataptic.Neat;
var Methods = neataptic.Methods;
var Config  = neataptic.Config;

/** Turn off warnings */
Config.warnings = false;

function createWorker(network, cost){
  // source is equivalent of test(), but without time recording
  var source = `
  ${network.standalone()}

  var cost = ${cost.toString()}
  onmessage = function(e) {
    console.log('Message received at', performance.now());
    var set = new Float64Array(e.data);
    var ins = set[0];
    var out = set[1];

    var error = 0;
    // Calculate how much samples are in the set
    for(var i = 0; i < (set.length - 2) / (ins + out); i++){
      let input = [];
      let target = [];
      for(var j = 2 + i * (ins + out); j < 2 + i * (ins + out) + ins; j++){
        input.push(set[j]);
      }
      for(var j = 2 + i * (ins + out) + ins; j < 2 + i * (ins + out) + ins + out; j++){
        target.push(set[j]);
      }

      let output = activate(input);
      error += cost(target, output);
    }

    var answer = new Float64Array([error / ((set.length - 2) / (ins + out))]);
    postMessage(answer.buffer, [answer.buffer]);
  }
  `;

  var blob = new Blob([source]);
  var blobURL = window.URL.createObjectURL(blob);
  var worker = new Worker(blobURL);

  return worker;
}

async function multiEvaluate(population, dataSet, cost){
  // Prepare the dataset to create a buffer
  var converted = [dataSet[0].input.length, dataSet[0].output.length];

  for(var i = 0; i < dataSet.length; i++){
    for(var j = 0; j < converted[0]; j++){
      converted.push(dataSet[i].input[j]);
    }
    for(var j = 0; j < converted[1]; j++){
      converted.push(dataSet[i].output[j]);
    }
  }

  return new Promise((resolve, reject) => {
    // Keep track of how many workers are finished
    var counter = 0;

    // Create a worker for every network, post a message
    for(var i = 0; i < population.length; i++){
      let genome = population[i];
      let worker = createWorker(genome, cost);
      worker.onmessage = function(e){
        genome.score = new Float64Array(e.data)[0];
        worker.terminate();
        if(++counter == population.length){
          resolve()
        }
      }

      let temp = new Float64Array(converted);
      console.log('Message sent at', performance.now());
      worker.postMessage(temp.buffer, [temp.buffer]);
    }
  });
}

async function f() {
  var network= new neataptic.Network(784,10);

  for(var i = 0; i < network.connections.length; i++){
    network.connections[i].weight = Math.random() * .02 - .01;
  }

  var neat = new neataptic.Neat(784, 10, null, {popsize: 1, network: network});
  for(var i = 0; i < 10; i++) neat.mutate();

  var set = mnist.set(500, 0).training;
  await multiEvaluate(neat.population, set, Methods.Cost.MSE);
}

f();

Does anyone know why the communication time is so slow in my code and not in the other questions code?

Edit: when I increase the amount of workers to start, the first arrival of a message will be after the last departure of a message... it seems like the webworkers don't start running after all the messages have been posted

Thomas Wagenaar
  • 6,489
  • 5
  • 30
  • 73
  • You are trying to create 100 workers? And yes, they can't start running as your JavaScript code for creating the workers is synchronous. Even if it was async, 100 workers (threads) is a lot. – XCS Jul 01 '17 at 16:16
  • @Cristy no, i'm only creating 1 and i'm noticing that the communication delay is quite bad. I just did a small test with 100 workers, and I noticed that the first one is only done after the last one has been instructed. But focus on the 1 worker example. – Thomas Wagenaar Jul 01 '17 at 16:20
  • So, can you post the code for only one worker and strip the unnecessary bits? What do you mean by "communication is slow" ? It might take some milliseconds for the worker to actually be created. – XCS Jul 01 '17 at 16:20
  • @Cristy the code in the question is the code for only one worker. I know it takes some milliseconds to create it, but i'm only measuring the time between message departure and message arrival (open console when running the JSFiddle linked in the question), it's way too big for buffered data. – Thomas Wagenaar Jul 01 '17 at 16:24
  • @Oh, I thought you were referring to `t0` and `t1` at the end of your code. – XCS Jul 01 '17 at 16:27
  • @Cristy oops, updated it – Thomas Wagenaar Jul 01 '17 at 16:29
  • If you find the solution please post the answer, I am curious about this too :) – XCS Jul 03 '17 at 09:52

0 Answers0