Para un próximo proyecto con node.js necesito realizar varias tareas de limpieza a intervalos periódicos. Específicamente, algunas tareas cada milisegundo, otras cada 20 ms (50 veces por segundo) y otras cada segundo. Así que pensé en usar setInterval(), con resultados divertidos: se saltaban muchas llamadas a funciones.node.js: setInterval() omitiendo llamadas
El punto de referencia I utilizada es la siguiente:
var counter = 0;
var seconds = 0;
var short = 1;
setInterval(function() {
counter ++;
}, short);
setInterval(function() {
seconds ++;
log('Seconds: ' + seconds + ', counter: ' +
counter + ', missed ' +
(seconds * 1000/short - counter));
}, 1000);
Hay una larga temporizador de un segundo y uno corto que se puede ajustar mediante la variable short
, en este caso de 1 ms. Cada segundo imprimimos la diferencia entre el número de tics esperados en el ciclo corto y el número real de veces que se actualizó el contador corto.
Aquí es cómo se comporta cuando el contador de tiempo corto es de 1 ms:
2012-09-14T23:03:32.780Z Seconds: 1, counter: 869, missed 131
2012-09-14T23:03:33.780Z Seconds: 2, counter: 1803, missed 197
2012-09-14T23:03:34.781Z Seconds: 3, counter: 2736, missed 264
...
2012-09-14T23:03:41.783Z Seconds: 10, counter: 9267, missed 733
Muchas llamadas a funciones se omiten. Aquí está para 10 ms:
2012-09-14T23:01:56.363Z Seconds: 1, counter: 93, missed 7
2012-09-14T23:01:57.363Z Seconds: 2, counter: 192, missed 8
2012-09-14T23:01:58.364Z Seconds: 3, counter: 291, missed 9
...
2012-09-14T23:02:05.364Z Seconds: 10, counter: 986, missed 14
Mejor, pero aproximadamente una llamada de función se salta cada segundo. Y durante 20 ms:
2012-09-14T23:07:18.713Z Seconds: 1, counter: 46, missed 4
2012-09-14T23:07:19.713Z Seconds: 2, counter: 96, missed 4
2012-09-14T23:07:20.712Z Seconds: 3, counter: 146, missed 4
...
2012-09-14T23:07:27.714Z Seconds: 10, counter: 495, missed 5
Finalmente durante 100 ms:
2012-09-14T23:04:25.804Z Seconds: 1, counter: 9, missed 1
2012-09-14T23:04:26.803Z Seconds: 2, counter: 19, missed 1
2012-09-14T23:04:27.804Z Seconds: 3, counter: 29, missed 1
...
2012-09-14T23:04:34.805Z Seconds: 10, counter: 99, missed 1
En este caso se salta muy pocas llamadas (la brecha aumentó a 2 después de 33 segundos y 3 después de 108 segundos
.Los números varían, pero son sorprendentemente consistentes entre ejecuciones: la ejecución del primer punto de referencia de 1 ms tres veces produjo un retraso después de 10 segundos de 9267, 9259 y 9253.
No he encontrado referencias para este problema en particular. Está este much cited Ressig post y muchas preguntas de JavaScript relacionadas, pero la mayoría asume que el código se ejecuta en un navegador y no en node.js.
Ahora para la temida pregunta: ¿qué está pasando aquí? Solo bromeaba; obviamente, las llamadas a funciones se están omitiendo. Pero no veo el patrón. Pensé que los ciclos largos podrían estar impidiendo los cortos, pero no tiene sentido en el caso de 1 ms. Las llamadas a funciones de ciclo corto no se superponen ya que solo actualizan una variable, y el proceso node.js está cerca del 5% de CPU incluso con un ciclo corto de 1 ms. El promedio de carga es alto, alrededor de 0.50. No sé por qué miles de llamadas estresan tanto mi sistema, ya que node.js maneja many more clients perfectly; debe ser cierto que setInterval() is CPU intensive (o estoy haciendo algo mal).
Una solución obvia es agrupar llamadas de función utilizando temporizadores más largos, y luego ejecutar llamadas de función de ciclo cortas muchas veces para simular un temporizador más corto. Luego use el ciclo largo como un "carro de escoba" que hace que las llamadas perdidas en los intervalos inferiores. Un ejemplo: configure llamadas de 20 ms y 1000 ms setInterval(). Para llamadas de 1 ms: llámalas 20 veces en la devolución de llamada de 20 ms. Para la llamada de 1000 ms: compruebe cuántas veces se ha llamado a la función de 20 ms (por ejemplo, 47), haga cualquier llamada restante (por ejemplo, 3). Pero este esquema va a ser un poco complejo, ya que las llamadas pueden superponerse de maneras interesantes; tampoco será regular aunque parezca así.
La verdadera pregunta es: ¿se puede hacer mejor, ya sea con setInterval() u otros temporizadores dentro de node.js? Gracias por adelantado.
¿Cómo? ¿Qué temporizadores de resolución, una biblioteca? – alexfernandez
Hay muchos scripts de temporizador de alta resolución en google.http: //www.sitepoint.com/creating-accurate-timers-in-javascript/ – zer02
No resolverá el problema actual. –