while nodejs node nexttick javascript node.js loops setinterval

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

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 con clearImmediate ().

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 y setTimeout 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.

process.nextTick

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); }