10
votes

Comment puis-je écrire Blocking dans stdout avec node.js?

J'écris une application nœud.js que STDOUT est pipiée dans un fichier. J'écris tout avec console.log. Après un moment, mon application atteint la limite de 1 Go et s'arrête. La chose intéressante est que si j'utilise la console.Error au lieu de console.log, l'utilisation de la mémoire est faible et le programme fonctionne bien. Donc, il semble que nœud.js ne puisse pas chasser le flux de stdout et tout est conservé en mémoire. Je veux garder STDRERR GRATUIT pour les erreurs.

Ma question est la suivante:

Y a-t-il un moyen d'écrire Blocking dans stdout? Ou du moins, puis-je écrire avec un rappel sur stdout afin que je puisse vous assurer que j'écris pas trop?

thx!


0 commentaires

5 Réponses :


0
votes

ne pas.

Ce que vous voulez faire est pause () Votre entrée lorsque la sortie est pleine, comme la méthode pompe () fait, puis CV () < / Code> Lorsque vous avez de la place pour écrire. Sinon, vos ballons de processus à la taille de Gargantuan.

Vous voulez probablement utiliser le plus direct SortiStream Stuff pour cela, cependant ou le écrire () appel, pas console.log () .


3 commentaires

Bien que la question de la performance particulière n'est pas une excellente motivation pour cela, il existe absolument des situations où vous faire veulent utiliser une écriture bloquante à la console. Par exemple, si vous travaillez avec async_hooks Moniteurs, vous ne pouvez pas utiliser de méthodes asynchrones dans les rappels d'écoute ASYNC (puisque l'écriture déclenchera elle-même l'auditeur et recueil pour toujours).


Pause et CV affecte la lecture, ne pas écrire.


Correct, mais c'est ce qui pousse la lecture et l'écriture de la boucle.



7
votes

écrire en utilisant processus.stdout.write < / Code> , la valeur de retour est de savoir si les données ont été tamponnées. Si c'est vrai, continuez à écrire lorsque processus.stdout émet l'événement drain .

Si vous souhaitez que votre code ait l'air synchronisé, utilisez Streamlinejs comme décrit ici: noeud. JS Stdout Flush


0 commentaires

18
votes

Si vous voulez vraiment vraiment des écrivies synchrones à STDOUT, vous pouvez faire:

var fs = require('fs');
fs.writeSync(1, "Foo\n");
fs.fsyncSync(1);


4 commentaires

C'est une excellente solution! Mais qu'est-ce que fs.fsyncsync (1) pour?


User698601: Assurez-vous que tout a été écrit sur le descripteur de fichier. L'un est stdout, deux est Stdrr, trois est Stdin.


On dirait que cette approche ne fonctionne pas lorsque la sortie de la tuyauterie sur stdout / stardr Stackoverflow.com/questions/50574243/... .


stdin est un descripteur de fichier zéro, pas trois



1
votes

Edit: Comme indiqué par le commentateur, cette solution a un problème. PrintResolver pourrait être transformé en une matrice, mais à l'aide de la solution supérieure est beaucoup plus facile

une fonction d'impression synchrone qui fonctionne également avec des tuyaux AKA FIFO's, en utilisant ASYNC / AWAIT. Assurez-vous de toujours appeler "Imprimer" avec "Await Imprimer" P>

let printResolver;
process.stdout.on('drain', function () {
    if (printResolver) printResolver();
});

async function print(str) {
    var done = process.stdout.write(str);
    if (!done) {
        await new Promise(function (resolve) {
            printResolver = resolve;
        });
    }
}


1 commentaires

Si impression est appelé deux fois avant drain se produit, le global printresolve sera remplacé et la promesse antérieure ne sera pas résolue.



1
votes

Le problème (l'utilisation de la mémoire d'explosement) se produit probablement parce que votre programme crée une sortie plus rapidement qu'il ne peut être affiché. Par conséquent, vous voulez le manipuler. Votre question demande "Sortie synchrone", mais le problème peut en réalité être résolu en utilisant un code purement "asynchrone" (*) (*).

(* Note: Dans ce terme "asynchrone" est utilisé dans ce post. le sens "JavaScript-Single-thread". Qui diffère du sens "multi-thread" conventionnel qu'une bouilloire entièrement différente de poisson).

Cette réponse montre comment " Le code asynchrone "peut être utilisé avec des promesses pour empêcher l'utilisation de la mémoire d'exploser par" pause "(par opposition à bloquer) l'exécution jusqu'à ce que la sortie d'écriture ait été bouleversée avec succès. Cette réponse explique également comment une solution de code asynchrone peut être avantageuse par rapport à une solution de code synchrone.

Q: "pause" sonne comme "bloqué" et comment le code asynchrone peut-il éventuellement "bloquer"? C'est un oxymoron!

A: Cela fonctionne car le moteur JavaScript V8 pause (blocs) Exécution de Seulement La tranche de code unique attend une promesse asynchrone à compléter, Tout en permettant d'autres tranches de code à exécuter entre-temps.

Voici une fonction d'écriture asynchrone (adaptée de ici ). xxx

Il peut être appelé à partir d'une fonction asynchreuse dans votre source code, par exemple
cas 1 xxx

principal () est la seule fonction appelée à partir du niveau supérieur. L'utilisation de la mémoire n'explosera pas car elle serait si appelée console.log ('Hello World'); .

Plus de contexte est nécessaire pour voir clairement l'avantage sur une véritable écriture synchrone :
cas 2 xxx

exécutant le code ci-dessus ( cas 2 ) montrerait que l'utilisation de la mémoire n'explose toujours pas ( identique à cas 1 ) parce que la tranche associée enregistreuse a été suspendue, mais l'utilisation de la CPU était toujours parce que la tranche d'essentielle n'était pas en pause est bon (pensez covid).

en comparaison, une solution synchrone bloquerait également le carrecteur essentiel .

Que se passe-t-il avec Plusieurs tranches appelant streamwrite ?
cas 3 xxx

Dans ce cas ( cas 3 ), l'utilisation de la mémoire est liée et le Essentialworker L'utilisation du processeur est élevé, la même chose que dans Case 2 . Lignes individuelles de Hello World et Goodbye World resterait atomique, mais les lignes ne remplaceraient pas proprement, par exemple xxx

pourrait apparaître.


0 commentaires