Last active
October 8, 2018 10:39
-
-
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!)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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