- Open your command-line application and navigate to your workspace.
- Create a new folder named 05-07-reading-shared-buffer-from-multiple-workers.
- Copy or create an index.html that loads and runs a main function from main.js.
- Create a main.js file with an onMessage function that logs out the following members of the message data: workenIndex, type, result, workerIndex, startIndex, endIndex, and windowSize:
// main.js
function onMessage(message) {
const {
type,
result,
workerIndex,
startIndex,
endIndex,
windowSize
} = message.data;
console.log(`Result from worker operation {
type: ${type},
result: ${result},
workerIndex: ${workerIndex},
startIndex: ${startIndex},
endIndex: ${endIndex},
windowSize: ${windowSize}
}`);
}
- Create a main.js file with a main method that defines constants for NUM_COUNT, BYTES_FOR_32_BIT, ARRAY_SIZE, WORKER_COUNT, and MAX_NUMBER:
export function main() {
console.log('Main function starting.');
const NUM_COUNT = 2048;
const BYTES_FOR_32_BIT = 4;
const ARRAY_SIZE = NUM_COUNT * BYTES_FOR_32_BIT;
const MAX_NUMBER = 32;
const WORKER_COUNT = 10;
}
- Next, create an array of workers of size WORKER_COUNT:
export function main() {
// ...
// create workers
let workers = [];
console.log('Creating workers.');
for (let i = 0; i < WORKER_COUNT; i++) {
const worker = new Worker('./worker.js');
worker.onmessage = onMessage;
workers = workers.concat(worker);
}
}
- Next, create a SharedArrayBuffer that is of size ARRAY_SIZE, and fill it with random integers:
export function main() {
// ...
// create buffer and add data
const sab = new SharedArrayBuffer(ARRAY_SIZE);
const intBuffer = new Int32Array(sab);
// fill with random numbers
console.log('Filling Int buffer');
intBuffer.forEach((value, index) => {
intBuffer[index] = (Math.random() * MAX_NUMBER) + 1;
});
}
- Post these messages to each of the workers: 'load-array', 'load-indices', 'calculate-sum', and 'calculate-average':
export function main() {
// ...
workers.forEach((worker, workerIndex) => {
worker.postMessage({ type: 'load-array', array: sab });
worker.postMessage({ type: 'load-indices', workerIndex,
workerCount: WORKER_COUNT });
worker.postMessage({ type: 'calculate-sum' });
worker.postMessage({ type: 'calculate-average' });
});;
}
- Create a worker.js file, assign the current context to a variable global, and declare variables named: sharedIntArray, sharedInArraySlice, workerIndex, workerCount, startIndex, and endIndex. Also, assign a function to the onmessage event:
// worker.js
const global = this;
let sharedIntArray;
let sharedIntArraylSlice;
let workerIndex;
let workerCount;
let startIndex;
let endIndex;
global.onmessage = (message) => {};
- In the onmessage listener, get the data component of the message argument and switch on the type attribute:
global.onmessage = (message) => {
const { data } = message;
switch (data.type) {}
};
- Add a case for 'load-array' where we assign the array property of data to sharedIntArray after casting it as an Int32Array:
global.onmessage = (message) => {
const { data } = message;
switch (data.type) {
case 'load-array':
sharedIntArray = new Int32Array(data.array);
break;
}
};
- Add a case for 'load-indices' that calculates the window of values that the current worker should work with, based on the current index and total number of workers:
global.onmessage = (message) => {
const { data } = message;
switch (data.type) {
case 'load-array':
sharedIntArray = new Int32Array(data.array);
break;
case 'load-indices':
workerIndex = data.workerIndex;
workerCount = data.workerCount;
const windowSize = Math.floor(sharedIntArray.length /
workerCount)
startIndex = windowSize * workerIndex;
const isLastWorker = workerIndex === workerCount - 1;
endIndex = (isLastWorker) ? sharedIntArray.length :
startIndex+windowSize;
sharedIntArraySlice = sharedIntArray.slice(startIndex,
endIndex);
break;
};
- Add a case for 'calculate-sum' that sums all the numbers in the array and posts the result back to the main thread:
global.onmessage = (message) => {
const { data } = message;
switch (data.type) {
// ...
case 'calculate-sum':
const sum = sharedIntArraySlice.reduce((acc, number) =>
acc + number
, 0);
sendResult('sum', sum);
break;
}
};
- Add a case for 'calculate-average' that averages all the numbers in the array and posts the result back to the main thread:
global.onmessage = (message) => {
const { data } = message;
switch (data.type) {
//...
case 'calculate-average':
const total = sharedIntArraySlice.reduce((acc, number) =>
acc + number
, 0);
const average = total / sharedIntArraySlice.length
sendResult('average', average);
break;
}
};
- Create a sendResult function that posts a result, a result type, and information about the current thread to the main thread:
function sendResult(type, result) {
global.postMessage({
type,
result,
workerIndex,
startIndex,
endIndex,
windowSize: endIndex - startIndex - 1
});
}
- Start your Python web server and open the following link in your browser:
http://localhost:8000/.
- You should see the following output: