parallel programming in JavaScript - javascript

I am working on sequential and parallel programming in javascript, I was able to solve sequential programming but didn't have an idea of how to do the same using parallel programming.
For Sequential problem was :
This is an example of sequential processing where it will start at 1 and go till 3 and add 21 to it. Then it will start at 1 and go till 2 and add 10 to it. In the end, start at 1 and go till 4 and add 1 to it.
For Input : 1 3*21#2*10#4*1
output will be :
22
23
24
11
12
2
3
4
5
I solved using below code
function solution(inputData) {
var first = inputData.substring(0, 1);
if(first == 1)
{
//sequential
var strArr = inputData.split(" "); //3*21#2*10#4*1
var strHashSplitArr = strArr[1].split("#"); //3*21 #2*10# 4*1
for(var i=0;i<strHashSplitArr.length;i++)
{
var loopInp = strHashSplitArr[i].split("*");
var maxVal = parseInt(loopInp[0]);
var addVal = parseInt(loopInp[1]);
for(var k=1;k<=maxVal;k++)
{
console.log(k+addVal);
}
}
}
}
But now the problem is with parallel programming
Problem:
For example 2, there are 3 processes to start in parallel and numbers are 1, 2 and 3 with delays 100, 20 and 50 consecutively. Here all the processes will start together but a number with less delay will be printed first. Here the number with less delay is 2.So it will print 21,22 in the meantime 50 ms will be achieved and it will print 51 from 3rd number. Now it is mixed with number 1 and prints 101 and so on.
Input : 2 1*100#2*20#3*50
Output should be :
21
22
51
101
52
53
I didn't try using parallels but sorted with milliseconds but couldn't get the expected output.
Here is JSfiddle code for 2nd .. which is giving wrong output (I am not using parallel approach) : https://jsfiddle.net/mahajan344/0u2ka981/
How can I achieve the same output using parallel JavaScript programming?

I think a solution for the problem using setTimeout may be:
function printParallel(val, delay)
{
setTimeout(function()
{
console.log(val);
}, delay);
}
function solution(inputData) {
var first = inputData.substring(0, 1);
var strArr = inputData.split(" ");
var strHashSplitArr = strArr[1].split("#");
for (var i = 0; i < strHashSplitArr.length; i++)
{
var loopInp = strHashSplitArr[i].split("*");
var maxVal = parseInt(loopInp[0]);
var modifier = parseInt(loopInp[1]);
if (first == 1)
{
for (var j = 1; j <= maxVal; j++)
{
console.log(j+modifier);
}
}
else if (first == 2)
{
for (var j = 1; j <= maxVal; j++)
{
printParallel(j+modifier, modifier);
}
}
}
}
So you will call solution("1 3*21#2*10#4*1"); and solution("2 1*100#2*20#3*50"); to execute the examples but this won't output as expected because the delay of 100 of number 1 is too big to mix with the printing of number 3.
EDIT:
I think now I understand the goal: yo need to set a timeout between every console.log. This will work as expected:
function printParallel(value, maxVal, modifier)
{
setTimeout(function()
{
console.log(value+modifier);
if (value < maxVal)
{
printParallel(++value, maxVal, modifier)
}
}, modifier);
}
function solution(inputData) {
var first = inputData.substring(0, 1);
var strArr = inputData.split(" ");
var strHashSplitArr = strArr[1].split("#");
for (var i = 0; i < strHashSplitArr.length; i++)
{
var loopInp = strHashSplitArr[i].split("*");
var maxVal = parseInt(loopInp[0]);
var modifier = parseInt(loopInp[1]);
if (first == 1)
{
for (var j = 1; j <= maxVal; j++)
{
console.log(j+modifier);
}
}
else if (first == 2)
{
printParallel(1, maxVal, modifier);
}
}
}

Consider:
async function delay(n) {
return new Promise(r => setTimeout(r, n));
}
async function* asyncRange(a, b, d) {
while (a < b) {
await delay(d);
yield a++;
}
}
async function parallel(...ranges_and_delays) {
let iters = ranges_and_delays.map(t => asyncRange(...t));
while (iters.length) {
await Promise.race(iters.map(async it => {
let v = await it.next();
if (!v.done) {
console.log(v.value)
} else {
iters = iters.filter(k => k !== it)
}
}));
}
}
parallel([1, 5, 700], [10, 13, 500], [200, 205, 600])
The idea is to put range generators in an array, start a race between them and print whatever comes first. Once a generator is exhausted, remove it from the list.
Note that this isn't real parallel computing (which is not possible in Javascript), just an imitation.

You cannot run your code in parallel in Javascript. It is single threaded language. However, you can use browser's web APIs to do work in parallel. For example, making xhr call.
Note: You cannot even run your code in parallel with SetTimeout() as it will only run the code when the call stack is empty. It does not actually run the code in parallel.
To develop an understanding of this, you must understand event loop.
https://www.educative.io/edpresso/what-is-an-event-loop-in-javascript

Related

Higher-order function

I have an exercise about JavaScript. This exercise requires me to use higher-order functions. I have managed to specify some of the functions so far, but when I try to execute the code, the result does not seem to work properly. I have some images to give you an idea, hopefully, you can help me correct this.
The thread is: Write the function loop(loops, number, func), which runs the given function the given number of times. Also write the simple functions halve() and square().
This is my code:
function loop(loops, number, func) {
var loops = function(n) {
for (var i = 0; i < n; i++) {
if (i < 0) {
console.log('Programme ended')
}
if (i > 0) {
return n;
}
}
}
}
var halve = function(n) {
return n / 2
}
var square = function(n) {
return n ** 2;
}
console.log(halve(50));
console.log(loop(5, 200, halve));
console.log(loop(3, 5, square));
console.log(loop(-1, 99, halve));
Your current loop function declares an inner function and then exits. Ie, nothing actually happens -
function loop(loops,number,func){
// declare loops function
var loops= function(n){
// ...
}
// exit `loop` function
}
One such fix might be to run the supplied func a number of times in a for loop, like #code_monk suggest. Another option would be to use recursion -
function loop (count, input, func) {
if (count <= 0)
return input
else
return loop(count - 1, func(input), func)
}
function times10 (num) {
return num * 10
}
console.log(loop(3, 5, times10))
// 5000
so first things first: Higher-Order functions are functions that work on other functions.
The reason why you get undefined is because you are calling a function which doesn't return anything.
function x(parameter){
result = parameter + 1;
}
// -> returns undefined every time
console.log(x(5));
// -> undefined
function y(parameter){
return parameter+1;
}
// -> returns a value that can be used later, for example in console.log
console.log(y(5));
// -> 6
Second, you are using n for your for loop when you should probably use loops so it does the intended code as many times as "loops" indicates instead of the number you insert (i.e. 200, 5, 99).
By having the "console.log" inside a loop you may get a lot of undesired "programme ended" in your output so in my version I kept it out of the loop.
The other two answers given are pretty complete I believe but if you want to keep the for loop here goes:
function loop(loops, number, func){
if(loops>0){
for(let i = 0; i< loops; i++){ // let and const are the new ES6 bindings (instead of var)
number = func(number)
}
return number
}
else{
return "Programme ended"
}
}
function halve(n) { // maybe it's just me but using function declarations feels cleaner
return n / 2;
}
function square(n) {
return n ** 2;
}
console.log(halve(50));
console.log(loop(5, 200, halve));
console.log(loop(3, 5, square));
console.log(loop(-1, 99, halve));
Here's one way
const loop = (loops, n, fn) => {
for (let i=0; i<loops; i++) {
console.log( fn(n) );
}
};
const halve = (n) => {
return n / 2;
};
const square = (n) => {
return n ** 2;
};
loop(2,3,halve);
loop(4,5,square);

How to pause a loop after x iterations for x seconds then resume

So I have an array that has a list of Channel Names that I would like to join (This is for a Twitch Chat Bot), the API endpoint for joining a channel has a rate limit of 50 joins per 15 seconds. I am trying to figure out the best way to iterate through 50 channel names, pause for 15 seconds, then resume iterating through the rest of the array, pausing for 15 seconds every 50 names.
I had originally tried a generic for loop using a fake, 100 value array, a Modulus Operator, and setTimeout, but to no avail. But in all honesty, I didn't know where to start so it is quite bad.
let array = ([...Array(100).keys()].map(x => ++x))
for (var i = 1; i < array.length; i++) {
if (i % 50 === 0) {
setTimeout(() => {
console.log('Waiting 15 seconds.')
}, 15000);
} else {
console.log(array[i])
}
}
Ideally, it would log 1-50, then wait 15 seconds, then log 51-100.
You can use async and await to pause your for loop in a fairly simple fashion:
// utility function that returns a promise that resolves after t milliseconds
function delay(t) {
return new Promise(resolve => {
setTimeout(resolve, t);
});
}
async function processArray(array) {
for (let i = 1; i < array.length; i++) {
if (i % 50 === 0) {
await delay(15 * 1000);
}
console.log(array[i])
}
}
let data = ([...Array(100).keys()].map(x => ++x))
processArray(data).then(() => {
console.log("all done");
});
FYI, I don't quite understand why you're trying to use index 1 through 100 on a 100 element array. I think you should be using indexes 0 through 99 for a 100 element array. I left the code that way you had in under the assumption that maybe you're doing this on purpose.
const _ = require('lodash');
Use iterators/generators so that you can control when you want the next item instead of fighting to "stop" the execution of the loop.
function* myIterator(data) {
for (const item of data)
yield item;
}
Then set up a function that will do the actual execution, taking the iterator as a parameter. This way, each time you call it, you can pass in the iterator so that it remembers where it left off.
function execute(it) {
// We want to do this in batches of 50
// (but test with lower value to better see how it works)
_.range(0, 50).forEach(() => {
// Get next item
const item = it.next();
// If no more items, we're done
if (item.done) return;
else {
// Do something with the item
console.log(item.value);
};
});
// Pause for 15 seconds and then continue execution
setTimeout(() => execute(it), 15000);
}
Create your data, generate an iterator from it and then execute.
(function main() {
const data = _.range(1, 101);
const it = myIterator(data);
execute(it);
})();
Try this
let array = ([...Array(100).keys()].map(x => ++x))
const startLoop = currentIndex => {
for (let i = currentIndex; i < array.length; i++) {
if (i % 50 === 0) {
setTimeout(() => {
console.log('Waiting 15 seconds.');
startLoop(i + 1);
}, 15000)
break;
}
console.log(array[i])
}
}
startLoop(1);
Writing a recursive loop function from scratch (at the cost of performance) is probably the simplest solution, but you can accomplish this iteratively using a while loop and a Promise, without compromising performance.
In the code below, every time the 1-based index of the loop reaches a multiple of batch_size, an await is called which stops execution until the Promise resolves. The promise is just a setTimeout call, which waits for pause_ms before allowing the loop to continue. The values are slightly different here just to make testing easier; you can change them freely to meet your needs.
const vals = [...new Array(20)].map(() => Math.floor(Math.random() * 9) + 1);
console.log(vals);
async function iterateBatches(arr, batch_size, pause_ms) {
// Create a promise generator that will automatically resolve after the desired number of millseconds.
const wait = () => new Promise(r => {
setTimeout(r, pause_ms)
});
// Establish the starting and ending points for the iteration.
const len = arr.length;
let i = 0;
// As long as the loop hasn't reached the final element,
while (i < len) {
// Perform an operation with the value in your array.
console.log(i, vals[i]);
// If we've reached the end of the array, break out of the loop to prevent an unneeded iteration.
if (i >= len - 1) break;
// Increment the index (this is also equal to the 1-based index, which saves us some lines).
// If the 1-based index is a multiple of batch_size and we're not on the first iteration, wait for our promise generator.
if (++i % batch_size === 0 && i > 0) await wait();
}
console.log("Done!");
}
iterateBatches(vals, 5, 2000);
You could just create the loop manually. Here's a simplified example...
var array = ['a','b','c','d','e','f'];
var i = 0;
function loop(){
if(i>=array.length) return;
if(i==3){
setTimeout(function(){
i++;
loop();
},15000);
return;
}
i++;
console.log(array[i]);
loop();
}
loop();

Techniques for having a node module return a "stream" of data?

I hope I'm asking the question correctly, but essentially, is there a way in NodeJS to have a CommonJS module return a stream of data instead of a finalized chunk of data after a (long) computation? Assuming there is more than one way, what are those techniques?
For example, say I have a findPrimes function, written as a CommonJS module:
find-primes.js
/**
* #module findPrimes
* #param {int} n - Find all primes less than this number
* #return {array}
*/
module.exports = function(n) {
if (n < 2) {
return [];
} else if (n === 2) {
return [2];
}
var primes = [2];
for (let i = 3; i < n; i += 2) {
let is_prime = true;
let sq = Math.ceil(Math.sqrt(i));
for (let t = 2; t <= sq; t++) {
if (i % t === 0) {
is_prime = false;
break;
}
}
if (is_prime) {
primes.push(i);
}
}
return primes;
};
As you can see, this function returns an array of all the prime numbers less than its input. It returns the array after it has computed all those numbers.
So, say I go to use this module in a node script
index.js
const primes = require('./find-primes.js');
// Usage: `node index.js <num>`
let primes_less_than = process.argv[2];
console.log(primes(primes_less_than));
When I run the above script with an arg of 25, I get the following (expected) output:
$ node index.js 25
[ 2, 3, 5, 7, 11, 13, 17, 19, 23 ]
However, say I passed in a much larger number, like 10,000,000
$ node index.js 10000000
# Takes a while to run before outputting the numbers...
While this works, ideally I'd like the program to start writing out the numbers it has computed before it finishes.
So my program would still take a while to run, but it would start outputting information to the screen much faster than "compute EVERYTHING first, then output ALL results".
What is the best way to achieve this effect? Streams? Promises?
I'm open to any and all techniques for this, thanks.
You'll have to use the Stream class from nodejs, and the method should export a callback with a stream as the commentaries said:
const stream = require('stream');
function getPrimesStream(n, cb) {
const primesStream = new stream.Stream();
cb(null, primesStream);
if (n >= 2) {
primesStream.emit('data', 2);
}
const primes = [2];
for (let i = 3; i < n; i += 2) {
let isPrime = true;
const sq = Math.ceil(Math.sqrt(i));
for (let t = 2; t <= sq; t += 1) {
if (i % t === 0) {
isPrime = false;
break;
}
}
if (isPrime) {
primesStream.emit('data', i);
primes.push(i);
}
}
return primes;
}
getPrimesStream(1000, function (err, stream) {
stream.on('data', function (data) {
console.log(data);
});
stream.on('end', function() {
console.log('finished');
});
});
You may use Node.js's stream module for this. It's hard to answer your question within a few lines of code, but if you are really interested in how streams work, have a look at this video (this is me giving a talk about Node.js streams at the Node.js meetup in Munich, Germany).
Alternatively, you may use a generator function with yield, but this as well is hard to explain from scratch in a few lines.
Anyway, streams and generator functions are the terms you should look for.

How to find the efficient sequence for my N number of sequence in Javascript

I am just trying find the right sequence in N number sequence.What I am talking about is Suppose we have 5 Machines and 20 jobs have to do in that machines.We will have the probability of 20! that is 2,432,902,008,176,640,000 possible sequence to do it right .What is best Sequence based on the time of completion.we have to find it.
Unfortunately I am little bit confused that how to get the right and best time efficient sequence.
Me stuck after producing the possibilities of sequence.And I don't Know how to get the right sequence
My try
var howManyMachines = 2;
var Sequenxe = [
{
jobId:1,
timeToFinish:5
},
{
jobId:2,
timeToFinish:4
},
{
jobId:3,
timeToFinish:4
}
];
var machines = Array(howManyMachines).fill().map((m, i) => {
var Mindex = i;
if(i == 0){
Mindex = 1
}else{
Mindex = i+1
}
return {
id: i,
value: 0,
jobs: [],
name:"M"+Mindex
} });
function permutations(items) {
if (items.length == 1) return [items];
var combos = [];
for (var i = 0; i < items.length; i++) {
var first = items[i], rest = items.slice(0);
rest.splice(i, 1);
permutations(rest).forEach(function(combo){
combo.unshift(first);
combos.push(combo);
});
}
return combos;
}
const allSequence = permutations(Sequenxe);
console.log(allSequence.length+" Sequence to test")
console.log(machines.length+" Machines Available");
allSequence.forEach(singleSequence => {
console.log("===>",singleSequence)
//I don't Know what to do
});
I think the only way to get a perfect solution is to check all the possibilities.
If you care about performance, this should but this should give you a correct solution in most cases while being reasonably quick ...
Main steps area:
Sort jobs by timeToFinish, longest to shortest
Add first job to the shortest thread
Sort threads by total time of execution, shortest to longest
Go to 2 and repeat until no more jobs available
var machines = 2;
var jobs = [{
jobId: 1,
timeToFinish: 5
}, {
jobId: 2,
timeToFinish: 4
}, {
jobId: 3,
timeToFinish: 4
}];
jobs.sort((a, b) => b.timeToFinish - a.timeToFinish);
var threads = new Array(2).fill({
jobs: [],
totalTime: 0
});
while (jobs.length > 0) {
threads = threads.map(t => {
j = jobs.shift();
return j ? {
jobs: t.jobs.concat(j),
totalTime: t.totalTime + j.timeToFinish
} : t;
});
threads.sort((a, b) => a.totalTime - b.totalTime);
}
console.log(JSON.stringify(threads, null, 2))
Best according to time of completion sounds like deadline scheduling.
Planning of these large jobs in advance sounds like the knapsack problem. I'd give knapsack.js a try. Source code is on GitHub.
You might do as follows; It will generate 20 jobs with random time for each and then will evenly distribute them into 5 machines.
function groupTasks(jobs,machineCount){
var sum = jobs.reduce((p,c) => p + c.time, 0),
initial = [...Array(machineCount)].map(sa => (sa = [], sa.sum = 0, sa));
console.log("total number of jobs:",jobs.length,"\n");
console.log("total job time:", sum,"\n");
console.log("number of machines:", machineCount,"\n");
console.log("target total job time per machine:", sum/machineCount,"\n");
return jobs.sort((a,b) => b.time-a.time)
.reduce((machines,job) => { var machine = machines.reduce((p,c) => p.sum < c.sum ? p : c);
machine.push(job);
machine.sum += job.time;
return machines;
},initial);
}
var jobs = [...Array(20)].map((_,i) => ({id:i, time:~~(Math.random()*10)+1})),
result = groupTasks(jobs,5);
console.log("jobs: \n", JSON.stringify(jobs));
console.log("jobs per machine:","\n",JSON.stringify(result));

Javascript - do something every x number of iterations in loop

I'm using the Google Maps API which has a limit of 10 requests per second. I want to have a short delay every 10 requests.
for (var i = 0; i < myRequests.length; i++) {
// pause every 10 iterations
}
My maths aren't sharp... How can I know whenever I reach 10 iterations in order to do something?
(function loop(z) {
for (var i = 0; i < 10; i++) {
//use myRequests[z]
console.log(myRequests[z]);
z++;
if(z===myRequests.length)
return;
}
setTimeout(function(){loop(z)},1000);
})(0);
DEMO
Create an array that stores the requests and use this:
var index = -1;
for(var i=0; i<anArray.length; i++){
if(anArray[i]!=false){
index = i;
break;
}
}
if(index!=-1){
function makeCall(){
//api calls
anArray[index] = true;
}
}else{
setTimeout(makeCall, 1000)
}
Loops can't wait
The only way to "wait" is to use a timeout, unfortunately for this situation timeouts are asynchronous, so they are useless in a loop because the loop will continue on anyway.
Instead, you will need to use a recursive function.
The math part
We can save a bunch of logic by using the modulo operator (%) to get the remainder of the currently incremented count divided by the split that you want to wait at. If the remainder is 0 (the current count is a multiple of the split), wait the requested amount of time.
Example
function log(out) { document.body.innerHTML += out; }
function repeat(count, split, limit, wait) {
var args = arguments;
if(++count <= limit) {
log([count, '0' + count][+(count < 10)] + ', ');
if(!(count % split) && count < limit) {
log('wait<br>');
setTimeout(function(){
repeat.apply(null, args);
}, wait);
} else repeat.apply(null, args);
} else log('done');
}
repeat(0, 10, 50, 1000);
You can use the modulus to determine, if you're in the 10th iteration.
for (var i = 0; i < myRequests.length; i++) {
// pause every 10 iterations
if (i%10==0){
sleep(5000)
}
}

Categories