Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support question / feature request - async.parallel with delay #1020

Closed
the1mills opened this issue Feb 4, 2016 · 11 comments
Closed

support question / feature request - async.parallel with delay #1020

the1mills opened this issue Feb 4, 2016 · 11 comments

Comments

@the1mills
Copy link

I am wondering if this is possible -

I want normal async.parallel / async.each funcitonality, but I want to be able to introduce a delay (using setTimeout) so that each successive function is guaranteed to start at certain amount of time after the previous, something like so:

async.parallel([
function one(cb){

//this functions starts running no earlier than at t = 0;

},
function two(cb){

//this function starts running no earlier than at t+=0.25

},
function three(cb){

//this function starts running no earlier than at t+=0.25..


},
function four(cb){

//this function starts running no earlier than at t+=0.25..


}], function complete(){

});

is this possible somehow with async? Is there a feature that can do this, or is there any easy why I could code that myself using async?

one solution, might look like this:

var delay = 0.25;
var t = 0;

async.each([1,2,3],function(item,cb){

    setTimeout(function(){

         cb(null);

     }, t+=delay);

}, function complete(){

});

thanks your help!

@aearly
Copy link
Collaborator

aearly commented Feb 9, 2016

What are your motivations for wanting to stagger execution of tasks? Would something like _.throttle work better?

@the1mills
Copy link
Author

LOL I can't remember exactly but I believe I still want it. I think the solution I have above is good enough for now. I think it had to do with not starting 10 child_processes at all once, but staggering them a bit.

@the1mills
Copy link
Author

the way it would go would be:

var delay = 0.25;
var t = 0;

async.each([1,2,3],function(item,cb){

    setTimeout(function(){

       doTheAsyncThing(function(err){
           cb(err);
      });

     }, t+=delay);

}, function complete(){

});

that should stagger things while still allowing for potential parallelism etc?

@megawac
Copy link
Collaborator

megawac commented Feb 10, 2016

Not quite @the1mills. This is also not provided currently by lodash (@aearly, throttle is different)


Such a feature is outside of the scope of asyncs offering but closer to several of lodash's methods (such as delay, once, throttle, etc). I would suggest you open up a ticket there if you have a concrete use case.

Anyway the correct implementation of what you're looking for is something like below (using es6 because I don't feel like codifying splats)

function lockForMs(fn, timeMs) {
    var unlockTime = Date.now() + timeMs;

    return function(/* args */) {
        var now = Date.now();
        if (now >= unlockTime) {
            fn.apply(this, arguments);
        } else {
            setTimeout(fn.bind(this, ...arguments), unlockTime - now);
        }
    };
}

You would then use this like

async.each([1,2,3],function(item,cb) {
      var lockedCb = lockForMs(cb, delay);
      doTheAsyncThing(lockedCb);
}, function complete(){

});

@megawac megawac closed this as completed Feb 10, 2016
@the1mills
Copy link
Author

@megawac can you explain what was wrong with my implementation? I am not seeing it. Perhaps our goals are different. My goal was simply to execute tasks in parallel but to ensure that each task was started at least a certain period of time (in this case .00025 sec) after the prior task. That was it. I think you are misunderestimating my code

@megawac
Copy link
Collaborator

megawac commented Feb 10, 2016

@the1mills you always wait delayms before trying to start the asynchronous action, whereas in my implementation you start the asynchronous action if it takes less than delay ms you wait the remaining time and then call the callback

@the1mills
Copy link
Author

nah you are misinformed, async.each will run those functions right after each other, so there is never a case where the async action takes less than the delay, do you follow? In other words, you should always wait for that delay period. I meant to make the delay more like 250 ms, not .25 ms.

@megawac
Copy link
Collaborator

megawac commented Feb 10, 2016

@the1mills setTimeout runs indepetendently from async which will ensure that your async function is always delayed:
delay ms + async ms + setTimeout implementation minimum ms

@the1mills
Copy link
Author

tomorrow I will create an example logging a timestamp and we can see :) I am not always right about these things

@the1mills
Copy link
Author

@megawac

this is what I discovered

var async = require('async');


var start = 0;
var diff = 250; //millis


async.each([1,2,3,4], function X(item,cb){

    console.log('started item=',item,'@',Date.now());

    setTimeout(function(){

        console.log('ran item=',item,'@',Date.now());
        cb(null);

    },start+=diff);


}, function complete(){

    console.log('All done @',Date.now());


});

output:

started item= 1 @ 1455141606290
started item= 2 @ 1455141606293
started item= 3 @ 1455141606294
started item= 4 @ 1455141606294
ran item= 1 @ 1455141606543
ran item= 2 @ 1455141606794
ran item= 3 @ 1455141607045
ran item= 4 @ 1455141607295
All done @ 1455141607296

as you can see for each item function X runs right after the one before (sometimes with a millisecond or two in between) but basically in the same millisecond and it's synchronous.

Therefore if your delay (in my case the diff variable) is >> 1 millisecond, then the logic above should be fine. Hope you agree. You can see that for each "ran item" line, there is almost exactly 250 millis staggering them.

@megawac
Copy link
Collaborator

megawac commented Feb 10, 2016

@the1mills 1) you should be using eachSeries rather than doing start+=diff 2) you removed the doTheAsyncThing from your code so you are literally only testing setTimeout rather than your implementation of delay

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants