Parallel and Distributed Algorithms - Part 2 - How to Get Things Done... Faster!
In today’s article, we’ll continue our journey in the land of parallel and distributed algorithms, but we’ll focus precisely on Parallel Algorithms with some hands-on examples using JavaScript.
Hello again, brave coder 👨💻. In today’s article, we’ll continue our journey in the land of parallel and distributed algorithms, but we’ll focus precisely on Parallel Algorithms with some hands-on examples using JavaScript. It’s going to be an awesome article packed with interesting information. Ready? Let’s go Ala Barakti Lah 🙏
What Are Parallel Algorithms Anyway?
Alright, so what is a parallel algorithm? In the simplest terms, it’s when you take a big task and split it into smaller tasks, letting them all run at the same time. Kind of like having multiple small workers running around, doing parts of your work simultaneously, instead of waiting for one to finish before the other starts.
PS: In JavaScript, you may think you're stuck with one lonely worker hahah (because JavaScript is single-threaded). But don’t worry! We can still make things happen in parallel. Let’s dive in!
Even though JavaScript typically does things one at a time, we can use a few tricks to get multiple things done at once. The Web Worker and Promises.
1. Web Workers:
Imagine you’re trying to solve a really hard math problem. But then, a magical helper (we’ll call them “Web Worker”) come to you and the problem gets solved in the background easily!
That’s what Web Workers do. They let you run code in a separate thread, so your main program doesn’t slow down.
Let’s see a simple example:
// main.js
const worker = new Worker('worker.js'); // Creating a worker
worker.onmessage = function(e) {
// The worker sends the result
console.log('The sum of the array is:', e.data);
};
// Send data to the worker
worker.postMessage([1, 2, 3, 4, 5]);
// worker.js
onmessage = function(e) {
const sum = e.data.reduce((acc, num) => acc + num, 0);
// Send the result back
postMessage(sum);
};
Here’s the explanation:
The main thread sends the array
[1, 2, 3, 4, 5]
to the worker.The worker does the math in the background.
The worker sends back the result!
2. Promises:
Now, what if you want to fetch data from several websites at once? Normally, JavaScript would fetch each website one by one, like a slow, waiter bringing out one dish at a time 👨🍳. Not anymore! Let’s make it fast with Promises.
async function fetchData() {
const urls = [
'https://api.example1.com',
'https://api.example2.com',
'https://api.example3.com'
];
// We fetch all URLs at once!
const responses = await Promise.all(urls.map(url => fetch(url)));
const data = await Promise.all(responses.map(response => response.json()));
console.log(data); // Logs data from all URLs
}
fetchData();
What’s happening here?
You ask JavaScript to fetch data from multiple URLs.
Promise.all makes sure all the fetches happen at the same time — no waiting around!
Once all the data is fetched, it’s displayed at once.
3. Parallel Map:
Okay, what if you have an array of numbers, and you want to square them, but you don’t want to do all the work yourself? No problem. Use parallel map!
Here’s the trick:
async function parallelMap(arr, func) {
return await Promise.all(arr.map(item => Promise.resolve(func(item))));
}
parallelMap([1, 2, 3, 4], x => x * x).then(result => console.log(result));
// Output: [1, 4, 9, 16]
What’s happening here?
You’ve got a list of numbers
[1, 2, 3, 4]
.You want to square each number, but you don’t want to do it one at a time.
With
Promise.all
, all the squaring happens at once, and the result is ready in no time!
4. Parallel Sorting:
Let’s talk about sorting, but not the old, boring way of doing it one item at a time. Parallel sorting splits the job into smaller chunks and sorts them in parallel!
Here’s a simple implementation of parallel sorting:
async function parallelMergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = parallelMergeSort(arr.slice(0, mid));
const right = parallelMergeSort(arr.slice(mid));
return merge(await left, await right);
}
function merge(left, right) {
let result = [], i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) result.push(left[i++]);
else result.push(right[j++]);
}
return result.concat(left.slice(i)).concat(right.slice(j));
}
parallelMergeSort([5, 3, 8, 1, 2, 7, 6, 4]).then(sorted => console.log(sorted));
// Output: [1, 2, 3, 4, 5, 6, 7, 8]
What’s happening here?
The array is split into two halves.
Each half is sorted in parallel by calling
parallelMergeSort
.The results are merged, and you get a sorted array, faster than ever.
⚠️Are there Any Problems Using the Approach?
Good question! Just because you’ve got a bunch of helpers doesn’t mean things can’t go wrong. Sometimes, race conditions happen when two workers try to do the same thing at once. It's like two people fighting over the last piece of a pizza 🍕
To avoid this, you can use things like locks or atomic operations to make sure only one worker is touching the dough at a time. But that's a story for another day. (Future article inshallah).
Wrapping Up Parallelism!
Now that you know a few tricks, you can make your JavaScript applications way faster by running tasks in parallel. Whether you’re squaring numbers, fetching data from APIs, or sorting large lists, parallel algorithms can save you time and help you avoid working alone!
Stay tuned, because in Part 3, we’ll dive into distributed algorithms, where things get even more interesting (and complicated, hahaha). But for now, you’ve learned how to make things happen faster with a little help from your parallel friends ;)
🔔 Don't forget to subscribe to my blog and YouTube channel to stay updated with all the latest content, follow me on LinkedIn too, if you like to do so!