Pourquoi est-impression sur la sortie standard si lent? Peut-il être accéléré?

J'ai toujours été étonné/frustré avec combien de temps cela prend simplement la sortie vers le terminal avec une instruction print. Après un récent lente et douloureuse de journalisation j'ai décidé de le regarder et a été très surpris de constater que presque tous le temps passé est en attente pour le terminal de traiter les résultats.

Peut écrire sur la sortie standard stdout être accéléré en quelque sorte?

J'ai écrit un script ('print_timer.py"au bas de cette question) pour comparer le timing lors de l'écriture de 100k lignes vers stdout vers un fichier, et avec stdout redirigé vers /dev/null. Voici le calendrier résultat:

$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print                         :11.950 s
write to file (+ fsync)       : 0.122 s
print with stdout = /dev/null : 0.050 s

Wow. Pour assurez-vous que python n'est pas de faire quelque chose de derrière les scènes, comme la reconnaissance que j'ai réassigné stdout vers /dev/null ou quelque chose, j'ai fait la redirection à l'extérieur du script...

$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print                         : 0.053 s
write to file (+fsync)        : 0.108 s
print with stdout = /dev/null : 0.045 s

Donc ce n'est pas un python truc, c'est juste le terminal. J'ai toujours su que le dumping de sortie vers /dev/null accéléré les choses, mais jamais pensé que c'était que d'importants!

Il me stupéfie comment ralentir le tty est. Comment se peut-il que l'écriture sur le disque physique est plus rapide que d'écrire sur le "écran" (sans doute un RAM op), et il est effectivement aussi vite que de simplement le dumping à la poubelle avec /dev/null?

Ce lien parle de la façon dont le terminal block I/O de sorte qu'il peut "parse [entrée], mise à jour de son mémoire d'image, de communication avec le serveur X pour faire défiler la fenêtre et ainsi de suite"... mais je ne suis pas entièrement l'obtenir. Ce peut être aussi long?

Je m'attends il n'y a pas moyen d'en sortir (à moins de un plus rapide ats mise en œuvre?) mais la figure que je vais demander de toute façon.


Mise à JOUR: après lecture de certains commentaires, je me demandais comment beaucoup d'impact sur ma taille de l'écran en fait sur le temps d'impression, et il ne ont leur importance. La très lente chiffres ci-dessus sont avec mon Gnome terminal soufflé jusqu'à 1920x1200. Si je le réduire très petit je obtenir...

-----
timing summary (100k lines each)
-----
print                         : 2.920 s
write to file (+fsync)        : 0.121 s
print with stdout = /dev/null : 0.048 s

C'est certainement mieux (~4x), mais ne change pas ma question. Il ne ajoute à ma question que je ne comprends pas pourquoi l'écran du terminal de rendu devrait ralentir une application d'écriture sur la sortie standard stdout. Pourquoi mon programme besoin d'attendre pour le rendu à l'écran pour continuer?

Sont tous en phase terminale/ats apps pas créés égaux? Je n'ai pas encore l'expérience. Il semble vraiment à moi comme un terminal devrait être en mesure de tampon toutes les données entrantes, analyser/rendre invisible, et que rendre la plus récente morceau qui est visible dans l'écran de configuration à un bon taux de trame. Donc, si je peux écrire+fsync à disque en de ~0,1 secondes, un terminal devrait être en mesure d'effectuer la même opération dans quelque chose de cet ordre (avec peut-être quelques mises à jour d'écran alors qu'il l'a fait).

Je suis encore un peu en espérant que il y a un ats paramètre qui peut être modifié à partir de l'application côté pour faire de ce comportement de mieux pour le programmeur. Si c'est strictement une application de terminal problème, alors ce peut-être n'a même pas sa place sur StackOverflow?

Ce qui me manque?


Voici le programme en python utilisé pour générer le calendrier:

import time, sys, tty
import os

lineCount = 100000
line = "this is a test"
summary = ""

cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
    print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

#Add a newline to match line outputs above...
line += "\n"

cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary
  • Le but entier de l'écriture sur la sortie standard est donc un homme peut lire le résultat. Aucun être humain dans le monde peut lire les 10 000 lignes de texte en 12 secondes, quel est donc le point de faire stdout plus vite???
  • Osewa: Un exemple (qui a conduit à ma question), c'est quand faisant des choses comme imprimer instruction de débogage. Vous souhaitez lancer votre programme et de voir les résultats comme ils se produisent. Vous êtes évidemment raison que la plupart des lignes à la mouche que vous ne pouvez pas voir, mais quand une exception se produit (ou vous frappez le conditionnel getch/raw_input/instruction de mise en veille vous soigneusement placé) vous voulez être à la recherche à la sortie d'impression directement, plutôt que de constamment avoir à ouvrir ou à l'actualisation d'un fichier de point de vue.
  • Imprimer instruction de débogage est l'une des raisons pour lesquelles les périphériques tty (c'est à dire les bornes) par défaut à la ligne de mise en mémoire tampon à la place du bloc de mise en mémoire tampon: la sortie de débogage n'est pas grande utilité si le programme se bloque et le dernier quelques lignes de sortie de débogage sont encore dans un tampon au lieu d'aboutir dans le terminal.
  • C'est pourquoi je n'ai pas pris la peine beaucoup à la poursuite d'énormes améliorations un intervenant revendiquée par manivelle jusqu'à la taille de la mémoire tampon. Entièrement défait le but de l'impression de débogage! J'ai fait l'expérience un peu lors de l'enquête, mais ne voit pas la nette amélioration. Je suis toujours curieux de connaître la différence, mais pas vraiment.
  • Parfois pour très longtemps programmes en cours d'exécution, je vais juste l'impression de la ligne actuelle stdout toutes les n secondes -- semblable à avoir un temps de rafraîchissement dans un malédictions app. Il n'est pas parfait, mais donne une idée de ce qui est où je suis à la fois dans un tout.
InformationsquelleAutor Russ | 2010-10-04