I have a node script which is supposed to utilize all the CPU resources a single node process could get. But I found setInterval to be too slow.
And sure enough I found this in the documentation:
When delay is larger than 2147483647 or less than 1, the delay will be
set to 1.
source: https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args
Now I wonder if there is a way to reduce the limit further or if there is an alternative function that I could use.
I can't just use a normal loop because there are other asynchronous things that need to run at the same time.
Edit:
Again: I can't just use a normal loop because there are other asynchronous things that need to run at the same time.
I'm not sure why this is so hard to understand.
While a normal loop is running, you are blocking the execution of everything else. It doesn't matter if you put the loop in another asynchronously executed function.
What does this mean?
Let's look at some examples:
setInterval(()=>{console.log('a')},1000) // asynchronous thing that needs to run in the background
while (true) {
// do whatever
}
What will this code do? It will block everything. console.log('a') will not be executed continuously.
setInterval(()=>{console.log('a')},1000) // asynchronous thing that needs to run in the background
setTimeout(()=>{
while (true) {
// do whatever
}
}, 1)
This will also block the execution of the intervals as soon as the while loop starts.
I believe the question belongs to node rather than to browser. You can use some of the following options (recursively/in loop) for reducing your delay time.
setImmediate
setImmediate - Schedules the "immediate" execution of the callback after I/O events' callbacks. Returns an Immediate for use with clearImmediate().
When multiple calls to setImmediate() are made, the callback functions are queued for execution in the order in which they are created. The entire callback queue is processed every event loop iteration. If an immediate timer is queued from inside an executing callback, that timer will not be triggered until the next event loop iteration.
It's from node guides:
setImmediate and setTimeout are similar, but behave in different
ways depending on when they are called.
setImmediate() is designed to execute a script once the current poll phase completes.
setTimeout() schedules a script to be run after a minimum threshold in ms has elapsed.
process.nextTick
The process.nextTick() method adds the callback to the "next tick
queue". Once the current turn of the event loop turn runs to
completion, all callbacks currently in the next tick queue will be
called.
From node guide
We recommend developers use setImmediate() in all cases because it's
easier to reason about (and it leads to code that's compatible with a
wider variety of environments, like browser JS.)
Thanks to Josh Lin for the idea to just run multiple intervals. I ended up with two simple wrapper functions for setInterval and clearInterval:
function setInterval2(cb,delay) {
if (delay >= 1)
return [setInterval(cb,delay)];
var intervalArr = [];
var intervalCount = Math.round(1/delay);
for (var i=0; i<intervalCount; i++)
intervalArr.push(setInterval(cb,1));
return intervalArr
}
function clearInterval2(intervalArr) {
intervalArr.forEach(clearInterval);
}
It works just like the original functions:
var count = 0;
// run interval every 0.01 milliseconds:
var foo = setInterval2(function(){
count++;
},0.01);
// stop execution:
clearInterval2(foo)
1 setInterval multiple times run more!
let count = 0,
by = 100,
_intervals = [],
timelimit = 100
for (let i = 0; i < by; i++) {
_intervals[i] = setInterval(() => count++, 1)
}
setTimeout(() => {
_intervals.forEach(x => clearInterval(x))
console.log(`count:${count}`)
}, timelimit)
2.setTimeout recurser run less!
let count = 0,
go = true
recurser()
setTimeout(() => {
go = false
console.log(`count:${count}`)
}, 100)
function recurser() {
count++
go && setTimeout(recurser)
}
3.requestAnimationFrame run less!
let count = 0,
go = true,
timelimit = 100
step()
setTimeout(() => {
go = false,
console.log(`count:${count}`)
}, timelimit)
function step() {
count++
go && requestAnimationFrame(step)
}
so as I know ,run setInterval multiple times, and I believe while will count more
You ask if it is possible to
run setInterval more than once per millisecond in nodejs
As you note in your question, this is not possible with setInterval, since there is always a minimum delay of at least 1 ms in node.js. In browsers, there is often a minimum delay of at least 10 ms.
However, what you want to achieve—to repeatedly run CPU-intensive code without unnecessary delay—is possible in other ways.
As noted in the answer by The Reason, setImmediate is a good option available in node.js. As setImmediate has limited browser support, and is unlikely to be widely supported in the future, there is another approach that also works in browsers.
While browsers enforce a minimum delay for setInterval and setTimeout, the delay for setTimeout is enforced from when the timer is set, not when it is run. If we use setTimeout repeatedly to call CPU-intensive code, we can make sure that a timer is always set 10–15 ms in advance (if the code takes at least 10–15 ms to run), thus reducing the actual delay to 0 ms.
The demo snippet below borrows code from this answer to demonstrate how the use of timers set in advance may make the delay smaller than what is enforced. In the browsers I tested, this usually results in a 0 ms delay.
// First: repeat runCPUForAtLeast50ms() 10 times
// with standard repeated setTimeouts and enforced delays
testTimeout(10, function(){
// Then: repeat runCPUForAtLeast50ms() 10 times
// using a repeated set of queued setTimeouts
// circumventing the enforced delays
testTimeout(10, false, true);
});
function testTimeout(repetitions, next, multiple) {
var delays = [];
var lastCheck;
var extraTimers;
function runner() {
if(lastCheck){
delays.push((+new Date) - lastCheck);
}
if(repetitions > 0) {
//process chunk
runCPUForAtLeast50ms();
//set new timer
setTimeout(runner);
} else if(repetitions === 0) {
//report result to console
console.log((multiple?
'Repeated multiple timers delays: ' :
'Repeated single timer delays: ') + delays.join(', '));
//invoke next() function if provided
next && next();
}
repetitions--;
lastCheck = +new Date;
}
setTimeout(runner);
if(multiple){
// make sure that there are always a fixed
// number of timers queued by setting extra timers
// at start
extraTimers = 10;
while(extraTimers--)
setTimeout(runner);
}
}
function runCPUForAtLeast50ms() {
var d = (+new Date) + 50;
while(+new Date < d);
}
I think you can solve your problem using async module... a way could be:
async.parallel([
(callback) => {
// do normal stuff
},
(callback) => {
// do your loop
}
], (err, results) => {
// ...
});
But take into account this note from the official documentation...
Note: parallel is about kicking-off I/O tasks in parallel, not about
parallel execution of code. If your tasks do not use any timers or
perform any I/O, they will actually be executed in series. Any
synchronous setup sections for each task will happen one after the
other. JavaScript remains single-threaded.
In short answer, you can't. There are some limitation of Javascript/Node as it is a single thread application. That's why you have async interrupts.
The long answer:
From the computer architecture's perspective, modern CPU and Kernel scheduling is not deterministic. If you want such fine grain control, I would suggest you look at MCU and embedded solutions that does not have a kernel scheduler. Because, your OS have many other processes and Kernel processes that takes up CPU time, so kernel scheduler have to keep scheduling different processes to be run on the CPU and meet many different demands.
Even with the set 1ms, when you try to measure, it is probably not 1ms (exact time depends on OS, hardware and amount of processes running on your computer).
Now, if you want to use all CPU resources, not possible.
But if you want to utilize as much as resources as possible, you can explore current programming pattern. For example, you can schedule 1 million threads (you machine probably won't be able to handle it), or some crazy large amount of processes and let your scheduler to be constantly putting process on your CPU, so there is no idle time and max out CPU utilization.
Alternatively, you can run CPU Stress tests, and those are designed to simply max out your CPU and keep it burning to high temperature -- make sure you have the cooling solution in place.
Related
Consider the two functions below, both async, one a brutal workload that takes a lot of time, and the other one a wait function that waits a precise number of seconds by setting a timeout.
async function Brutal_Workload()
{
for(var x = 0; x< 1000 * 1000 * 1000; x++)
{
}
}
async function Time_Wait(seconds)
{
var promise = new Promise((resolve, reject) =>
{
var msecs = Math.floor(seconds * 1000);
var timer =
setTimeout(
function()
{
clearTimeout(timer);
resolve();
},
msecs);
});
return promise;
}
Now, let's call the first function in a setInterval cycle
setInterval(
async function()
{
await Brutal_Workload();
console.log("BLIP");
}, 1000 / 30);
All as intended: despite the interval running at 30 calls per second, I only get 1 blip per second, because Brutal_Workload is choking it.
But when I use the other function...
setInterval(
async function()
{
await Time_Wait(1);
console.log("BLIP");
}, 1000 / 30);
I get 30 BLIPs per second.
The Time_Wait function, which works otherwise just fine outside of setInterval, doesn't seem to work here.
Any idea of what might cause this behavior?
Ok, rather than continue the back-and-forth in the comments, I'm just going to post this as an answer.
Javascript is both single-threaded and concurrent. I know you know this, but you don't seem to realize the implications. In your first function, you only see a console.log every so often, because your "brutal workload" blocks the only thread of execution until it completes, which means that regardless of what number you passed to setInterval not only is no other invocation running, the next bit of work isn't even being queued to run because your brutal workload is blocking the only thread of execution.
Understand, the runtime environment's setInterval runs on the same (only) thread as your code, the JS engine doesn't cheat and run your stuff in one thread and setInterval in another. So while brutal workload is doing its thing, setInterval itself, much less the function you passed to it, is not running at all. Using async and wrapping your brutal workload in a Promise makes essentially zero difference in terms of our discussion here, because brutal workload dominates.
So that explains the first example, so far so good. On to the second.
Unlike the first example, in the second there is no long-running chunk of code to tie up the thread of execution. So your callback to setInterval runs, dutifully registers a thing to run in a second, and yields control of the thread of execution, something that again the first example does not (and cannot do). Here the Promise and async/await actually does enable concurrency which it can't do in the first example because brutal workload is hogging the thread. So in a fraction of a second your callback to setInterval runs again, dutifully queues up another thing to run after a second has passed, and so on.
So after ~1 second that first queued up log happens, and then after a fraction of a second after that the second, and then so on. This doesn't happen in the first example because although you told setInterval to run 30x/sec brutal workload means that setInterval itself can't run to even queue your callback to be ran.
I need to execute an operation that needs to be executed relatively fast (let's say 10 times per second. It should be fast enough, but I can sacrifice speed if there are issues.) This is an ajax request, so potentially I do not know how much time it takes - it could even take seconds if network is bad.
The usual:
setInterval(() => operation(), 100);
Will not work here, because if the network is bad and my operation takes more than 100 ms, It might be scheduled one after another, occupying JS engine time (please correct me if I'm wrong)
The other possible solution is to recursively run it:
function execute() {
operation();
setTimeout(execute, 100);
}
This means that there will be 100 ms between the calls to operation(), which is OK for me. The problem with this is that I'm afraid that it will fail at some point because of stack overflow. Consider this code:
i = 0;
function test() { if (i % 1000 == 0) console.log(i); i++; test(); }
If I run it my console, this fails in around 12000 calls. if I add setTimeout in the end, this would mean 12000 / 10 / 60 = 20 minutes, potentially ruining the user experience.
Are there any simple ways how to do this and be sure it can run for days?
There's no "recursion" in asynchronous JavaScript. The synchronous code (the test function) fails because each call occupies some space in the call stack, and when it reaches the maximum size, further function calls throw an error.
However, asynchrony goes beyond the stack: when you call setTimeout, for example, it queues its callback in the event loop and returns immediately. Then, the code, that called it can return as well, and so on until the call stack is empty. setTimeout fires only after that.
The code queued by setTimeout then repeats the process, so no calls accumulate in the call stack.
Therefore, "recursive" setTimeout is a good solution to your problem.
Check this example (I recommend you to open it in fullscreen mode or watch it in the browser console):
Synchronous example:
function synchronousRecursion(i){
if(i % 5000 === 0) console.log('synchronous', i)
synchronousRecursion(i+1);
//The function cannot continue or return, waiting for the recursive call
//Further code won't be executed because of the error
console.log('This will never be evaluated')
}
try{
synchronousRecursion(1)
}catch(e){
console.error('Note that the stack accumuates (contains the function many times)', e.stack)
}
/* Just to make console fill the available space */
.as-console-wrapper{max-height: 100% !important;}
Asynchronous example:
function asynchronousRecursion(i){
console.log('asynchronous',i)
console.log('Note that the stack does not accumuate (always contains a single item)', new Error('Stack trace:').stack)
setTimeout(asynchronousRecursion, 100, i+1);
//setTimeout returns immediately, so code may continue
console.log('This will be evaluated before the timeout fires')
//<-- asynchronusRecursion can return here
}
asynchronousRecursion(1)
/* Just to make console fill the available space */
.as-console-wrapper{max-height: 100% !important;}
The two alternatives you showed here actually share the flaw you're concerned about, which is that the callbacks might bunch up and run together. Using setTimeout like this is (for your purposes) identical to calling setInterval (except for some small subtleties that don't apply with a light call like making an AJAX request.)
It sounds like you might want to guarantee that the callbacks run in order, or potentially that if multiple callbacks come in at once, that only the most recent one is run.
To build a service that runs the most recent callback, consider a setup like this:
let lastCallbackOriginTime = 0;
setInterval(()=>{
const now = new Date().getTime();
fetch(url).then(x=>x.json()).then(res=>{
if ( now > lastCallbackOriginTime ) {
// do interesting stuff
lastCallbackOriginTime = now;
}
else console.log('Already ran a more recent callback');
});
}, 100);
Or let's make it run the callbacks in order. To do this, just make each callback depend on a promise returned by the previous one.
let promises = [Promise.resolve(true)];
setInterval(()=>{
const promise = new Promise((resolve, reject)=> {
fetch(url).then(x=>x.json()).then(serviceResponse=>{
const lastPromise = promises[promises.length - 1];
lastPromise.then(()=>resolve(serviceResponse));
}).then((serviceResponse)=>{
// Your actual callback code
});
promises.push(promise)
});
}, 100);
There are several libraries (especially for NodeJS and Javascript) that allow you to implement cron jobs and subsequently host them on a server.
In essence, cron jobs seem to me nothing more than repetitive tasks that are executed at a specific time/date on a day.
I was wondering therefore what the difference is between these libraries and just let's say a custom while loop. For instance in Javascript we could write:
var keepRunning = true
while (keepRunning) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000);
}
My questions are therefore:
why do we use cron job libraries? What are the benefits above a custom function like above?
This would not work as you might expect:
var keepRunning = true
while (keepRunning) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000);
}
That code will schedule new setTimeout callbacks as fast as it can while keepRuning is true, never unwinding the call stack and letting the event loop run any of those callbacks. It will likely consume all of your memory without running the scheduled code even once.
What you can do is something like this:
var keepRunning = true;
function run() {
if (keepRunning) {
// call function to be executed when time constraint satisfied
setTimeout(run, 5000);
}
}
setTimeout(run, 5000);
If you want to schedule all the callbacks at once, then you might do something like this:
for (let i = 1; i <= 100; i++) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000 * i);
}
but in this example you need to multiply the timeout by the iteration variable to make sure that they are not scheduled to run at the same time - i.e. they are still scheduled all at once but they are later run at different times.
Remember that JavaScript runs to completion and callbacks are executed later when the call stack unwinds. It's also important that for and while loops block the event loop from executing and no event can be handled while the loop is running.
Cron handles very time specific events far better than this. If you wanted something to happen at 9am each day you would absolutely have to use Cron over some method like this.
Cron measures time from epoch and is the most accurate way of scheduling tasks. I would also imagine it would result in better performance than what you are suggesting.
Why would you NOT use Cron?
A library is a collection of useful code. Those collections tend to group up a significant amount of functions, objects, etc.
Your example was just one situation that had very little versatility. Libraries would provide much more options for your loop, and would go beyond just addressing the rate, but also other factors (depending on what specific library you are referring to).
Is there a faster alternative to window.requestAnimationFrame() for endless loops that don't block I/O?
What I'm doing in the loop isn't related to animation so I don't care when the next frame is ready, and I have read that window.requestAnimationFrame() is capped by the monitor's refresh rate or at least waits until a frame can be drawn.
I have tried the following as well:
function myLoop() {
// stuff in loop
setTimeout(myLoop, 4);
}
(The 4 is because that is the minimum interval in setTimeout and smaller values will still default to 4.) However, I need better resolution than this.
Is there anything with even better performance out there?
I basically need a non-blocking version of while(true).
Two things that will run sooner than that setTimeout:
process.nextTick callbacks (NodeJS-specific):
The process.nextTick() method adds the callback to the "next tick queue". Once the current turn of the event loop turn runs to completion, all callbacks currently in the next tick queue will be called.
This is not a simple alias to setTimeout(fn, 0). It is much more efficient. It runs before any additional I/O events (including timers) fire in subsequent ticks of the event loop.
Promise settlement notifications
So those might be a tools for your toolbelt, doing a mix of one or both of those with setTimeout to achieve the balance you want.
Details:
As you probably know, a given JavaScript thread runs on the basis of a task queue (the spec calls it a job queue); and as you probably know, there's one main default UI thread in browsers and NodeJS runs a single thread.
But in fact, there are at least two task queues in modern implementations: The main one we all think of (where setTimeout and event handlers put their tasks), and the "microtask" queue where certain async operations are placed during the processing of a main task (or "macrotask"). Those microtasks are processed as soon as the macrotask completes, before the next macrotask in the main queue — even if that next macrotask was queued before the microtasks were.
nextTick callbacks and promise settlement notifications are both microtasks. So scheduling either schedules an async callback, but one which will happen before the next main task.
We can see that in the browser with setInterval and a promise resolution chain:
let counter = 0;
// setInterval schedules macrotasks
let timer = setInterval(() => {
$("#ticker").text(++counter);
}, 100);
// Interrupt it
$("#hog").on("click", function() {
let x = 300000;
// Queue a single microtask at the start
Promise.resolve().then(() => console.log(Date.now(), "Begin"));
// `next` schedules a 300k microtasks (promise settlement
// notifications), which jump ahead of the next task in the main
// task queue; then we add one at the end to say we're done
next().then(() => console.log(Date.now(), "End"));
function next() {
if (--x > 0) {
if (x === 150000) {
// In the middle; queue one in the middle
Promise.resolve().then(function() {
console.log(Date.now(), "Middle");
});
}
return Promise.resolve().then(next);
} else {
return 0;
}
}
});
$("#stop").on("click", function() {
clearInterval(timer);
});
<div id="ticker"> </div>
<div><input id="stop" type="button" value="Stop"></div>
<div><input id="hog" type="button" value="Hog"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
When you run that and click the Hog button, note how the counter display freezes, then keeps going again. That's because of the 300,000 microtasks that get scheduled ahead of it. Also note the timestamps on the three log messages we write (they don't appear in the snippet console until a macrotask displays them, but the timestamps show us when they were logged).
So basically, you could schedule a bunch of microtasks, and periodically let those run out and run the next macrotask.
Note: I've used setInterval for the browser example in the snippet, but setInterval, specifically, may not be a good choice for a similar experiment using NodeJS, as NodeJS's setInterval is a bit different from the one in browsers and has some surprising timing characteristics.
there are some libs that can work like cron task, e.g., https://www.npmjs.com/package/node-cron
i think that using cron should be easier, and more flexible.
The following code is taken from Project Silk (a Microsoft sample application)
The publish method below loops thru an an array of event callBacks and executes each one. Instead of using a for loop setInterval is used instead.
The documentation says this allows each subscriber callback to be invoked before the previous callback finishes. Is this correct? I thought the browser would not allow the execution of the function inside the interval to run until all prior executions of it had finished.
Is this really any different than doing a for loop?
that.publish = function (eventName, data)
{
var context, intervalId, idx = 0;
if (queue[eventName])
{
intervalId = setInterval(function ()
{
if (queue[eventName][idx])
{
context = queue[eventName][idx].context || this;
queue[eventName][idx].callback.call(context, data);
idx += 1;
}
else { clearInterval(intervalId); }
}, 0);
}
Using setInterval here does make the execution sort of "asynchronous", because it schedules the execution of the callback for the next time the main execution thread is available.
This means that the callback executions should not block the browser because any other synchronous processing will take place before the callbacks (because the callbacks are scheduled to run only when the main execution thread has a spare millisecond) - and that's what makes this construct "better" than a regular for loop - the fact that the callbacks won't block the browser and cause the dreaded "This page has a script that's taking too long" error.
The side effect of this scheduling pattern is that the timeout is only a "suggestion" - which is why they use 0 here.
See: http://ejohn.org/blog/how-javascript-timers-work/
setInterval(..., 0) can be used to yield control to the browser UI, to prevent it from freezing if your code takes a long time to run.
In this case, that.publish will exit almost immediately before any callback has been executed. Each callback will then run "in the background" - they will be placed in the event loop, and each one will yield to the browser to do it's thing before the next callback is executed.
This seems like a good idea in event processing, because you don't want event processing to freeze the browser even if there are a lot of them or some take a long time to finish.
About the documentation - as stated, it is incorrect. Javascript is single-threaded. But if you were to call publish() a few times in a row, it is true that those calls would all finish before any callbacks are executed, because of the setTimeout. Maybe this is what the documentation means?