node.js: setInterval () ignore les appels
Pour un projet à venir avec node.js j'ai besoin pour effectuer diverses tâches d'entretien périodiques fois. Plus précisément certaines tâches à chaque milliseconde, d'autres toutes les 20 ms (50 fois par seconde) et d'autres encore à chaque seconde. J'ai donc pensé à utiliser la fonction setInterval(), avec des drôles de résultats: de nombreux appels de fonction ont été ignorées.
La référence que j'ai utilisé est comme suit:
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);
Il y a un timer long d'un deuxième et d'un court qui peut être ajusté à l'aide de la variable short
dans ce cas, 1 ms. Chaque seconde nous imprimer la différence entre le nombre de tiques dans le cycle court et le nombre de fois que le court compteur a été mis à jour.
Ici est de savoir comment il se comporte quand le timer court est 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
De nombreux appels de fonction sont ignorés. Ici, il est de 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
Mieux, mais à peu près un appel de fonction est ignorée à chaque seconde. Et pour les 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
Enfin pour 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
Dans ce cas, il saute très peu d'appels (l'écart est passé à 2, après 33 secondes et 3 après 108 secondes.
Les chiffres varient, mais sont étonnamment cohérente entre les pistes: l'Exécution de la première 1 ms référence à trois reprises donné un délai au bout de 10 secondes de 9267, 9259 et 9253.
Je n'ai pas trouvé de références pour ce problème particulier. Il y a cette beaucoup cité Ressig post et beaucoup de JavaScript liées à des questions, mais la plupart supposent que le code s'exécute dans un navigateur et non dans node.js.
Maintenant, pour la terrible question: ce qui se passe ici? Juste plaisanter; il est évident que les appels de fonction sont ignorés. Mais je n'arrive pas à voir le modèle. Je pensais que les cycles longs qui pourrait empêcher les courts, mais il n'a pas de sens dans le 1 cas de sp. Cycle court des appels de fonction sont chevauchent pas puisqu'ils ont juste de mettre à jour une variable, et la node.js le processus est de près de 5% de CPU, même avec un cycle court de 1 ms. La charge moyenne est élevée, même si, à environ 0.50. Je ne sais pas pourquoi d'un millier d'appels sont en insistant sur mon système autant, bien que, depuis node.js poignées beaucoup plus de clients parfaitement; il doit être vrai que setInterval() est l'UC (ou je fais quelque chose de mal).
Une solution évidente est de regrouper les appels de fonction à l'aide de plus longues, et puis exécutez le cycle court des appels de fonction plusieurs fois pour simuler une courte minuterie. Ensuite, utilisez le cycle long comme une "voiture-balai", qui rend tout d'appels manqués dans la partie inférieure des intervalles. Un exemple: 20 ms et 1000 ms setInterval() appelle. Pour 1 ms appels: appeler 20 fois dans les 20 ms de rappel. Pour les 1000 ms appel: vérifier combien de fois les 20ms fonction a été appelée (p. 47), n'importe quel restant appels (par exemple 3). Mais ce schéma va être un peu complexe, car les appels peuvent se chevaucher de manière intéressante, aussi il ne sera pas régulière, bien qu'il puisse ressembler.
La vraie question est: peut-il être fait mieux, avec setInterval() ou d'autres minuteurs dans les node.js? Merci à l'avance.
source d'informationauteur alexfernandez
Vous devez vous connecter pour publier un commentaire.
SetInterval des fonctions en javascript ne sont pas exactes. Vous devriez essayer d'utiliser une résolution élevée de la minuterie.La construction exacte de Minuteurs dans javascript
Regarder cette doc: http://nodejs.org/api/timers.html#timers_settimeout_callback_delay_arg
Cela se produit parce que le code de l'application bloque la boucle d'événements. Tous les compteurs à zéro et I/O les événements peuvent être traitées uniquement sur le
nextTick
.Vous pouvez voir ce comportement avec ce code:
Essayer de changer itérations de comptage et de voir les résultats.
Idéalement, la minuterie sera déclenchée exactement si les applications de la tique va durer moins d'un ms. Mais ce n'est pas possible dans une application réelle.
La réponse se trouve être une combinaison de ceux donnés par Vadim et zer02, je suis donc en laissant une écriture-up ici. Que Vadim a dit, le système ne peut pas faire face à trop de mises à jour fréquentes, et l'ajout d'une charge pour le système ne va pas les aider. Ou plutôt le moteur d'exécution ne peuvent pas faire face; le système devrait être plus que capable de tirer le rappel de toutes les millisecondes si nécessaire, mais pour une raison inexpliquée souvent, il ne veut pas.
La solution est d'utiliser précision des chronomètrescomme zer02 commenté. Ne pas être induit en erreur par le nom; le mécanisme utilisé est le même setTimeout(), mais le retard est ajustée en fonction du temps restant jusqu'à ce que la minuterie doit se déclencher. Donc, si le temps n'est plus alors le "précis de la minuterie" lancera un appel setTimeout(callback, 0) qui est exécuté immédiatement. La charge du système est, de façon surprenante, moins de setInterval(): environ 2% de l'UC au lieu de 5%, à mon très peu scientifique de l'échantillon.
Cette simple fonction peut être utile:
À utiliser, il suffit d'appeler
new timer(delay, callback);
. (Oui, j'ai inversé l'ordre des paramètres depuis d'avoir le rappel de la première est très ennuyeux.)Une dernière remarque: setTimeout(callback, retard) ne pas utiliser la récursivité comme je le craignais (comme dans: attendre pendant un certain temps, puis appeler la fonction de rappel), c'est juste des lieux de la fonction de rappel dans une file d'attente qui sera appelée par le moteur d'exécution lorsque son tour arrive, dans le contexte mondial.