Laissez-moi vous donner un exemple:
$ timeout 1 yes "GNU" > file1
$ wc -l file1
11504640 file1
$ for ((sec0=`date +%S`;sec<=$(($sec0+5));sec=`date +%S`)); do echo "GNU" >> file2; done
$ wc -l file2
1953 file2
Ici, vous pouvez voir que la commande yes
écrit 11504640
lignes dans une seconde pendant que je peux écrire seulement 1953
lignes en 5 secondes à l'aide de Bash for
et echo
.
Comme suggéré dans les commentaires, il existe différentes astuces pour le rendre plus efficace, mais rien ne se rapproche de la vitesse de yes
:
$ ( while :; do echo "GNU" >> file3; done) & pid=$! ; sleep 1 ; kill $pid
[1] 3054
$ wc -l file3
19596 file3
$ timeout 1 bash -c 'while true; do echo "GNU" >> file4; done'
$ wc -l file4
18912 file4
Ceux-ci peuvent écrire jusqu'à 20 mille lignes dans une seconde. Et ils peuvent être encore améliorés pour:
$ timeout 1 bash -c 'while true; do echo "GNU"; done >> file5'
$ wc -l file5
34517 file5
$ ( while :; do echo "GNU"; done >> file6 ) & pid=$! ; sleep 1 ; kill $pid
[1] 5690
$ wc -l file6
40961 file6
Ceux-ci nous amènent jusqu'à 40 mille lignes dans une seconde. Mieux, mais toujours un cri loin de yes
qui peut écrire environ 11 millions de lignes dans une seconde!
Donc, Comment yes
écrire dans le fichier si rapidement?
Une meilleure question serait la raison pour laquelle votre shell écria-t-il le fichier si lentement. Tout programme compilé autonome qui utilise la rédaction de fichiers syscalls de manière responsable (ne pas rincer tous les caractères à la fois) le ferait raisonnablement rapide. Ce que vous faites, c'est écrire des lignes dans un interprété Langue (la coquille) et, en outre, vous faites un lot de inutile opérations de sortie d'entrée. Qu'est-ce que yes
fait:
Quel est votre script:
date
et stockez sa sortie (uniquement dans la version originale - dans la version révisée, vous gagnez un facteur 10 en ne le faisant pas)echo
commande, reconnaissez-la (avec un code de correspondance de modèle) en tant que coque intégrée, d'une expansion des paramètres d'appel et de tout le reste de l'argument "GNU", et écrivez enfin la ligne au fichier ouvert.Les parties coûteuses: toute l'interprétation est extrêmement chère (BASH effectue une énormément de prétraitement de toutes les entrées - votre chaîne pourrait potentiellement contenir une substitution variable, une substitution de processus, une expansion de la corset, des caractères d'échappement, etc.), chaque appel d'une invention est Probablement une instruction de commutation avec redirection vers une fonction qui traite de la construction, et de manière très important, vous ouvrez et fermez un fichier pour chaque ligne de sortie. Vous pourriez mettre >> file
En dehors de la boucle tandis que la boucle pour le faire beaucoup plus rapide, mais vous êtes toujours dans une langue interprétée. Vous avez beaucoup de chance que echo
est une coque intégrée, pas une commande externe - sinon, votre boucle impliquerait la création d'un nouveau processus (Fork & Exec) sur chaque itération. Ce qui empêcherait le processus à une halte - vous avez vu à quel point une commande est coûteuse lorsque vous aviez la commande date
dans la boucle.
Les autres réponses ont abordé les points principaux. Sur une note latérale, vous pouvez augmenter le débit de votre boucle de votre temps en écrivant au fichier de sortie à la fin du calcul. Comparer:
$ i=0;time while [ $i -le 1000 ]; do ((++i)); echo "GNU" >>/tmp/f; done;
real 0m0.080s
user 0m0.032s
sys 0m0.037s
avec
$ i=0;time while [ $i -le 1000 ]; do ((++i)); echo "GNU"; done>>/tmp/f;
real 0m0.030s
user 0m0.019s
sys 0m0.011s