while nodejs node nexttick loop node.js settimeout

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.