Skip to content

Instantly share code, notes, and snippets.

@janbaykara
Last active October 8, 2018 10:39
Show Gist options
  • Save janbaykara/b9e8b50b00b705c58600c067eeca8cdd to your computer and use it in GitHub Desktop.
Save janbaykara/b9e8b50b00b705c58600c067eeca8cdd to your computer and use it in GitHub Desktop.
Organise batch operations on an array by Web Workers, in conjunction with workerize-loader (or any other promise-ified Web Worker implementation!)
import Worker from 'somewhere'
// ...
const piranhas = new Piranhas(
// Worker constructor
Worker,
// Listens for messages from workers
e => { e.data.type === 'INCREMENT' && someIncrementer() }
)
try {
const particles = await piranhas.process(
someArray,
// Buils an array of Promises to fulfill
(worker, arrayChunk) => worker.generateParticles(arrayChunk)
)
} catch (e) {
console.warn(e.error)
}
piranhas.kill()
/**
* Handles multithread processing on an array through promise-ified Web Workers
* (through workerize-loader https://github.com/developit/workerize-loader)
*
* @example
* const piranhas = new Piranhas(
* Worker,
* // Listens for messages from workers
* e => { e.data.type === 'INCREMENT' && someIncrementer() }
* )
*
* try {
* const particles = await piranhas.process(
* someArray,
* // Buils an array of Promises to fulfill
* (worker, arrayChunk) => worker.generateParticles(arrayChunk)
* )
* } catch (e) {
* console.warn(e.error)
* }
*
* piranhas.kill()
*/
export default class Piranhas {
workers = []
threadN = 0
/**
* Spin up the workers
* @param {Constructor} Worker constructor to instantiate threadN times
* @param {Function} onMessage listen for webworker messages
* @param {Number} threadN number of workers to instantiate
*
* @public
*/
constructor(
Worker = Worker,
onMessage = console.log,
threadN = window ? window.navigator.hardwareConcurrency : 8
) {
this.threadN = threadN
for (let i = 0; i < threadN; i++) {
const w = new Worker()
w.onmessage = onMessage
this.workers.push(w)
}
}
/**
* Run an operation over an array
* splitting the work between all the workers
* @param {Array} array of data to split up and work on
* @param {Function} operation function with takes a worker instance, a subset of `array`
* @returns {Promise} from a workerize'd Web Worker
* @return {Promise}
*
* @public
*/
process = async (array, operation) => {
const chunkedArray = chunks(array, this.threadN)
const batches = await Promise.all(
Array(this.threadN)
.fill(0)
.map((_, n) => operation(this.workers[n], chunkedArray[n]))
)
return [].concat(...batches)
}
/**
* Kill all the workers
*
* @public
*/
kill = () => {
this.workers.forEach(w => {
if (w.terminate) w.terminate()
})
}
}
function chunks(arr, chunksN) {
arr = JSON.parse(JSON.stringify(arr))
const chunkSize = Math.ceil(arr.length / chunksN)
var results = []
while (arr.length) {
results.push(arr.splice(0, chunkSize))
}
return results
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment