javascript - nexttick - setinterval nodejs
Permite ejecutar setInterval más de una vez por milisegundo en nodejs (6)
Tengo una secuencia de comandos de nodo que se supone que utiliza todos los recursos de CPU que un proceso de nodo único podría obtener. Pero encontré setInterval demasiado lento.
Y efectivamente encontré esto en la documentación:
Cuando el retraso es mayor que 2147483647 o menor que 1, el retraso se establecerá en 1.
fuente: https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args
Ahora me pregunto si hay una manera de reducir aún más el límite o si hay una función alternativa que podría usar.
No puedo usar un bucle normal porque hay otras cosas asíncronas que deben ejecutarse al mismo tiempo.
Editar:
De nuevo: no puedo usar un bucle normal porque hay otras cosas asíncronas que deben ejecutarse al mismo tiempo. No estoy seguro de por qué esto es tan difícil de entender.
Mientras se está ejecutando un ciclo normal, está bloqueando la ejecución de todo lo demás. No importa si coloca el bucle en otra función ejecutada de forma asíncrona.
¿Qué significa esto?
Veamos algunos ejemplos:
setInterval(()=>{console.log(''a'')},1000) // asynchronous thing that needs to run in the background
while (true) {
// do whatever
}
¿Qué hará este código? Bloqueará todo. console.log(''a'')
no se ejecutará de forma continua.
setInterval(()=>{console.log(''a'')},1000) // asynchronous thing that needs to run in the background
setTimeout(()=>{
while (true) {
// do whatever
}
}, 1)
Esto también bloqueará la ejecución de los intervalos tan pronto como comience el bucle while.
1 setInterval
varias veces correr más!
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 corre menos!
let count = 0,
go = true
recurser()
setTimeout(() => {
go = false
console.log(`count:${count}`)
}, 100)
function recurser() {
count++
go && setTimeout(recurser)
}
3.requestAnimationFrame corre menos!
let count = 0,
go = true,
timelimit = 100
step()
setTimeout(() => {
go = false,
console.log(`count:${count}`)
}, timelimit)
function step() {
count++
go && requestAnimationFrame(step)
}
así que como sé, ejecute setInterval
varias veces, y creo que while
cuente más
Creo que la pregunta pertenece al nodo en lugar de al navegador. Puede usar algunas de las siguientes opciones (recursivamente / en bucle) para reducir su tiempo de demora.
setImmediate
: programa la ejecución "inmediata" de la devolución de llamada después de las devoluciones de llamada de eventos de E / S. Devuelve un Inmediato para su uso conclearImmediate
().Cuando se realizan varias llamadas a setImmediate (), las funciones de devolución de llamada se ponen en cola para su ejecución en el orden en que se crearon. La cola de devolución de llamada completa se procesa cada iteración de bucle de evento. Si se pone en cola un temporizador inmediato desde el interior de una devolución de llamada en ejecución, ese temporizador no se activará hasta la siguiente iteración del bucle de evento.
Es de las guías de node
:
setImmediate
ysetTimeout
son similares, pero se comportan de diferentes maneras dependiendo de cuándo se llaman.
setImmediate()
está diseñado para ejecutar un script una vez que se completa la fase de sondeo actual.setTimeout(
) programa una secuencia de comandos para ejecutarse después de que haya transcurrido un umbral mínimo en ms.
El método
process.nextTick()
agrega la devolución de llamada a la "siguiente cola de marcación". Una vez que el turno actual del bucle de eventos se complete, se llamarán todas las devoluciones de llamada que se encuentran actualmente en la siguiente cola de tics.
De la guía de node
Recomendamos que los desarrolladores utilicen setImmediate () en todos los casos porque es más fácil de razonar (y conduce a un código que es compatible con una variedad más amplia de entornos, como el navegador JS).
Creo que puedes resolver tu problema usando un módulo async ... una forma podría ser:
async.parallel([
(callback) => {
// do normal stuff
},
(callback) => {
// do your loop
}
], (err, results) => {
// ...
});
Pero ten en cuenta esta nota de la documentación oficial ...
Nota: en paralelo se trata de iniciar tareas de E / S en paralelo, no de ejecución paralela de código. Si sus tareas no utilizan temporizadores ni realizan ninguna E / S, en realidad se ejecutarán en serie. Cualquier sección de configuración síncrona para cada tarea sucederá una después de la otra. JavaScript sigue siendo de un solo hilo.
En breve respuesta, no puedes. Hay algunas limitaciones de Javascript / Nodo, ya que es una aplicación de un solo hilo. Por eso tienes interrupciones asíncronas.
La respuesta larga: desde la perspectiva de la arquitectura de la computadora, la programación moderna de CPU y Kernel no es determinista. Si desea un control de grano fino, le sugeriría que busque en MCU y soluciones integradas que no tengan un programador de kernel. Debido a que su sistema operativo tiene muchos otros procesos y procesos de Kernel que consumen tiempo de CPU, el programador del kernel debe seguir programando diferentes procesos para que se ejecuten en la CPU y cumplan con muchas demandas diferentes.
Incluso con el conjunto de 1 ms, cuando intenta medir, probablemente no sea 1 ms (el tiempo exacto depende del sistema operativo, el hardware y la cantidad de procesos que se ejecutan en su computadora).
Ahora, si desea utilizar todos los recursos de la CPU, no es posible.
Pero si desea utilizar la mayor cantidad de recursos posible, puede explorar el patrón de programación actual. Por ejemplo, puede programar 1 millón de subprocesos (su máquina probablemente no podrá manejarlo), o una gran cantidad de procesos locos y dejar que su programador esté constantemente poniendo proceso en su CPU, por lo que no hay tiempo de inactividad y Máxima utilización de CPU.
Alternativamente, puede ejecutar pruebas de estrés de la CPU, y están diseñadas para limitar al máximo su CPU y mantenerla a una temperatura elevada. Asegúrese de tener la solución de enfriamiento en su lugar.
Gracias a Josh Lin por la idea de ejecutar múltiples intervalos. Terminé con dos funciones simples de envoltorio para setInterval
y 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);
}
Funciona igual que las funciones originales:
var count = 0;
// run interval every 0.01 milliseconds:
var foo = setInterval2(function(){
count++;
},0.01);
// stop execution:
clearInterval2(foo)
Preguntas si es posible
ejecuta setInterval más de una vez por milisegundo en nodejs
Como observa en su pregunta, esto no es posible con setInterval
, ya que siempre hay un https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args En los navegadores, a menudo hay un retraso mínimo de al menos 10 ms .
Sin embargo, lo que quiere lograr, ejecutar repetidamente el código de uso intensivo de la CPU sin demoras innecesarias, es posible de otras maneras.
Como se señaló en la respuesta de The Reason , setImmediate
es una buena opción disponible en node.js. Como setImmediate
tiene un soporte de navegador limitado, y es poco probable que sea ampliamente compatible en el futuro , existe otro enfoque que también funciona en los navegadores.
Mientras que los navegadores imponen un retraso mínimo para setInterval
y setTimeout
, el retraso para setTimeout
se aplica cuando se establece el temporizador, no cuando se ejecuta. Si utilizamos setTimeout
repetidamente para llamar al código intensivo de la CPU, podemos asegurarnos de que siempre se establezca un temporizador con 10–15 ms de antelación (si el código tarda al menos 10–15 ms en ejecutarse), lo que reduce el retraso real a 0 Sra.
El fragmento de demostración a continuación toma el código de esta respuesta para demostrar cómo el uso de los temporizadores programados por adelantado puede hacer que la demora sea más pequeña de lo que se aplica. En los navegadores que probé, esto generalmente resulta en un retraso de 0 ms.
// 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);
}