node.js - nexttick - set delay nodejs
¿Cómo se implementa setTimeout en node.js (2)
No hay problema con muchos temporizadores! Cuando la encuesta de llamada de bucle uv, le pasa un argumento de tiempo de espera al temporizador más cercano de todos los temporizadores.
[temporizador más cercano de todos los temporizadores]
https://github.com/joyent/node/blob/master/deps/uv/src/unix/timer.c # 120
RB_MIN(uv__timers, &loop->timer_handles)
[pasar argumento de tiempo de espera para sondear api]
https://github.com/joyent/node/blob/master/deps/uv/src/unix/core.c # 276
timeout = 0;
if ((mode & UV_RUN_NOWAIT) == 0)
timeout = uv_backend_timeout(loop);
uv__io_poll(loop, timeout);
Nota: en el sistema operativo Windows, es casi la misma lógica
Me preguntaba si alguien sabe cómo se implementa setTimeout en node.js. Creo que he leído en alguna parte que esto no es parte de V8. Intenté rápidamente encontrar la implementación, pero no pude encontrarla en la fuente (BIG). Por ejemplo, encontré este archivo timers.js , que luego, por ejemplo, enlaza con timer_wrap.cc . Pero estos archivos no responden completamente a todas mis preguntas.
- ¿V8 tiene implementación
setTimeout
? Supongo que también de la fuente la respuesta es no. ¿Cómo se implementa
setTimeout
? javascript o nativo o combinación de ambos? De timers.js asumo algo en la línea de ambos:var Timer = process.binding(''timer_wrap'').Timer;`
Cuando se agregan varios temporizadores (setTimeout), ¿cómo node.js sabe cuál ejecutar primero? ¿Agrega todos los temporizadores a una colección (ordenada)? Si está ordenado, entonces encontrar el tiempo de espera que debe ejecutarse es O (1) y O (log n) para la inserción. Pero entonces otra vez en timers.js los veo usar una lista enlazada?
- Pero, de nuevo, agregar un montón de temporizadores no es un problema en absoluto?
Al ejecutar este script:
var x = new Array(1000), len = x.length; /** * Returns a random integer between min and max * Using Math.round() will give you a non-uniform distribution! */ function getRandomInt (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } var y = 0; for (var i = 0; i < len; i++) { var randomTimeout = getRandomInt(1000, 10000); console.log(i + '', '' + randomTimeout + '', '' + ++y); setTimeout(function () { console.log(arguments); }, randomTimeout, randomTimeout, y); }
¿Tienes un poco de uso de CPU pero no tanto?
- Me pregunto si implemento todas estas devoluciones de llamada una por una en una lista ordenada si obtendré un mejor rendimiento.
Ya has hecho la mayor parte del trabajo. V8 no proporciona una implementación para setTimeout
porque no es parte de ECMAScript. La función que utiliza se implementa en timers.js, que crea una instancia de un objeto Timeout
que es un contenedor alrededor de una clase C.
Hay un comentario en la fuente que describe cómo están administrando los temporizadores.
// Because often many sockets will have the same idle timeout we will not
// use one timeout watcher per item. It is too much overhead. Instead
// we''ll use a single watcher for all sockets with the same timeout value
// and a linked list. This technique is described in the libev manual:
// http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Be_smart_about_timeouts
Lo que indica que está utilizando una lista de doble enlace que es # 4 en el artículo vinculado.
Si no hay una solicitud, sino muchas miles (millones ...), todas empleando algún tipo de tiempo de espera con el mismo valor de tiempo de espera, entonces uno puede hacerlo aún mejor:
Al iniciar el tiempo de espera, calcule el valor del tiempo de espera y ponga el tiempo de espera al final de la lista.
Luego use un ev_timer para disparar cuando se espera que se active el tiempo de espera al principio de la lista (por ejemplo, utilizando la técnica # 3).
Cuando haya alguna actividad, elimine el temporizador de la lista, vuelva a calcular el tiempo de espera, añádalo nuevamente al final de la lista y asegúrese de actualizar el ev_timer si se tomó desde el principio de la lista.
De esta manera, se puede administrar un número ilimitado de tiempos de espera en O (1) tiempo para iniciar, detener y actualizar los temporizadores, a costa de una complicación importante, y tener que usar un tiempo de espera constante. El tiempo de espera constante garantiza que la lista permanezca ordenada.
Node.js está diseñado para operaciones asíncronas y setTimeout
es una parte importante de eso. No trataría de ponerme difícil, solo uso lo que proporcionan. Confíe en que es lo suficientemente rápido hasta que haya probado que en su caso específico es un cuello de botella. No te quedes estancado en la optimización prematura.
ACTUALIZAR
Lo que sucede es que básicamente tiene un diccionario de tiempos de espera en el nivel superior, por lo que todos los tiempos de espera de 100 ms se agrupan. Cada vez que se agrega un nuevo tiempo de espera, o los desencadenantes de tiempo de espera más antiguos, se anexa a la lista. Esto significa que el tiempo de espera más antiguo, el que se activará más pronto, se encuentra al principio de la lista. Hay un solo temporizador para esta lista, y se establece en función del tiempo hasta que el primer elemento de la lista caduque.
Si llama a setTimeout
1000 veces cada una con el mismo valor de tiempo de espera, se agregarán a la lista en el orden en que llamó a setTimeout
y no es necesario realizar ninguna clasificación. Es una configuración muy eficiente.