Parallel Execution: The Pattern
Learn about patterns in parallel execution and how to fix race conditions with concurrent tasks.
We'll cover the following...
The pattern
Finally, we can extract our nice little pattern for the parallel execution flow. Let’s represent a generic version of the pattern with the following code:
Press + to interact
function makeSampleTask (name) {return (cb) => {console.log(`${name} started`)setTimeout(() => {console.log(`${name} completed`)cb()}, Math.random() * 2000)}}const tasks = [makeSampleTask('Task 1'),makeSampleTask('Task 2'),makeSampleTask('Task 3'),makeSampleTask('Task 4')]let completed = 0tasks.forEach(task => {task(() => {if (++completed === tasks.length) {finish()}})})function finish () {// all the tasks completedconsole.log('All tasks executed!')}
With small modifications, we can adapt the pattern to accumulate the results of each task into a collection, to filter or map the elements of an array, or to invoke the finish()
callback as soon as one or a given number of tasks are completed (this last situation in particular is called competitive race). ...