Quel est le moyen le plus rapide d'exécuter un script?

22

Je me demandais quel est le moyen le plus rapide d'exécuter un script, j'ai lu qu'il y avait une différence de vitesse entre afficher la sortie du script sur le terminal, le rediriger vers un fichier ou peut-être /dev/null.

Donc, si la sortie n'est pas importante, quel est le moyen le plus rapide de faire fonctionner le script plus rapidement, même s'il est minimal.

bash ./myscript.sh 
-or-
bash ./myscript.sh > myfile.log
-or-
bash ./myscript.sh > /dev/null
Kingofkech
la source
En relation: Y a
Wildcard
Comparer "rediriger vers un fichier normal" et "rediriger vers / dev / null" me semble tellement bizarre ...
el.pescado

Réponses:

31

De nos jours, les terminaux sont plus lents qu'auparavant, principalement parce que les cartes graphiques ne se soucient plus de l'accélération 2D. Ainsi, en effet, l'impression sur un terminal peut ralentir un script, en particulier lorsque le défilement est impliqué.

Par conséquent, ./script.shest plus lent que ./script.sh >script.log, ce qui à son tour est plus lent que /script.sh >/dev/null, car ces derniers impliquent moins de travail. Cependant, la question de savoir si cela fait suffisamment de différence pour un usage pratique dépend de la quantité de sortie produite par votre script et de la vitesse. Si votre script écrit 3 lignes et se ferme, ou s'il imprime 3 pages toutes les quelques heures, vous n'avez probablement pas à vous soucier des redirections.

Edit: Quelques repères rapides (et complètement cassés):

  • Dans une console Linux, 240x75:

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    3m52.053s
    user    0m0.617s
    sys     3m51.442s
    
  • Dans un xterm, 260x78:

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    0m1.367s
    user    0m0.507s
    sys     0m0.104s
    
  • Rediriger vers un fichier, sur un disque Samsung SSD 850 PRO 512 Go:

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >file)
     real    0m0.532s
     user    0m0.464s
     sys     0m0.068s
    
  • Rediriger vers /dev/null:

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >/dev/null)
     real    0m0.448s
     user    0m0.432s
     sys     0m0.016s
    
Satō Katsura
la source
6
@Kingofkech, c'est moins de 200 lignes / seconde. Cela ne ferait pas beaucoup de différence. (À titre de comparaison, timeout 1 yes "This is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"imprime plus de 100000 lignes en une seconde sur mon MBP.)
muru
4
@Kingofkech S'il s'agit d'un script, modifiez un fichier et commentez la ligne qui imprime une sortie inutile. Vous gagnerez beaucoup, surtout s'il s'agit d'une commande externe (non intégrée au shell) exécutée 3 millions de fois ...
jimmij
2
Pour une interprétation étroite de "utilisé pour être". Un terminal vt220 est beaucoup plus lent que les émulateurs de terminaux d'aujourd'hui. De plus, les postes de travail SUN Sparc (ceux que j'ai utilisés) avaient une console très lente, donc simplement rediriger la sortie vers un fichier lors de la compilation d'un projet plus grand accélérerait énormément le temps de compilation.
Kusalananda
1
@Kusalananda C'est vrai, xterms sur HP Apollo d'il y a 30 ans utilisé pour ramper par rapport à xtermsHP-UX d'il y a 20 ans. Cependant, une console Linux avec une carte vidéo Matrox d'il y a 15 ans était plus lente que la même console Linux avec une carte S3 d'il y a 20 ans. Et une console Linux avec un tampon de trame haute résolution sur une carte moderne est tout simplement inutilisable. :)
Satō Katsura
6
@Kingofkech C'est environ 2400 bps. Certains d'entre nous ont vécu pendant des années avec ces vitesses. :)
Satō Katsura
14

J'aurais instinctivement accepté la réponse de Satō Katsura; Ca a du sens. Cependant, c'est assez facile à tester.

J'ai testé l'écriture d'un million de lignes à l'écran, l'écriture (ajout) dans un fichier et la redirection vers /dev/null. J'ai testé chacun d'eux tour à tour, puis j'ai fait cinq répétitions. Ce sont les commandes que j'ai utilisées.

$ time (for i in {1..1000000}; do echo foo; done)
$ time (for i in {1..1000000}; do echo foo; done > /tmp/file.log) 
$ time (for i in {1..1000000}; do echo foo; done > /dev/null)

J'ai ensuite tracé le total des temps ci-dessous.

tracé du temps par rapport à la sortie

Comme vous pouvez le voir, les présomptions de Satō Katsura étaient correctes. Selon la réponse de Satō Katsura, je doute également que le facteur limitant soit la sortie, il est donc peu probable que le choix de la sortie ait un effet substantiel sur la vitesse globale du script.

FWIW, ma réponse d'origine avait un code différent, qui avait le fichier ajouté et /dev/nullredirigé à l' intérieur de la boucle.

$ rm /tmp/file.log; touch /tmp/file.log; time (for i in {1..1000000}; do echo foo >> /tmp/file.log; done) 
$ time (for i in {1..1000000}; do echo foo > /dev/null; done)

Comme le souligne John Kugelman dans les commentaires, cela ajoute beaucoup de frais généraux. La question actuelle, ce n'est pas vraiment la bonne façon de le tester, mais je vais le laisser ici car il montre clairement le coût de la réouverture d' un fichier à plusieurs reprises à partir de l' intérieur du script lui - même.

tracé du temps par rapport à la sortie

Dans ce cas, les résultats sont inversés.

Sparhawk
la source
FWIW J'ai ajouté une référence rapide à ma réponse. Notamment, la console Linux est> 200 fois plus lente qu'un an xterm, ce qui est à son tour ~ 3 fois plus lent que /dev/null.
Satō Katsura du
Vous devez également tester avec une certaine limitation de débit. La sortie de l'OP est d'environ 200 lignes / s.
muru
@muru Voulez-vous dire imprimer une ligne, attendre 1/200 secondes, puis répéter? Je peux essayer, mais je pense que ce seront des résultats similaires, mais prenez juste beaucoup plus de temps pour que le signal surmonte le bruit. Bien que je puisse peut-être soustraire le temps d'attente avant l'analyse.
Sparhawk
@Sparhawk quelque chose comme ça. Je pense qu'à ce niveau de sortie, le CPU aura beaucoup de temps pour mettre à jour l'affichage sans ralentir le taux de sortie. Lorsque le programme ne fait rien mais crache des lignes sans pause, les tampons du terminal se remplissent plus rapidement que l'affichage ne peut être mis à jour et crée un goulot d'étranglement.
muru
3

Une autre façon d'accélérer un script est d'utiliser un interpréteur de shell plus rapide. Comparez les vitesses d'une boucle occupée POSIX , exécutée sous bash v4.4 , ksh v93u + 20120801 et dash v0.5.8 .

  1. bash:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | bash -s > /dev/null

    Sortie:

    real    0m25.146s
    user    0m24.814s
    sys 0m0.272s
  2. ksh:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | ksh -s > /dev/null

    Sortie:

    real    0m11.767s
    user    0m11.615s
    sys 0m0.010s
  3. dash:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | dash -s > /dev/null

    Sortie:

    real    0m4.886s
    user    0m4.690s
    sys 0m0.184s

Un sous - ensemble de commandes dans bashet kshsont rétrocompatibles avec toutes les commandes dans dash. Un bashscript qui utilise uniquement des commandes dans ce sous-ensemble devrait fonctionner avec dash.

Certains bashscripts qui utilisent de nouvelles fonctionnalités peuvent être convertis en un autre interpréteur. Si le bashscript s'appuie fortement sur des fonctionnalités plus récentes, cela ne vaut peut-être pas la peine - certaines nouvelles bashfonctionnalités sont des améliorations qui sont à la fois plus faciles à coder et plus efficaces, (bien bashqu'elles soient généralement plus lentes), de sorte que l' dashéquivalent (qui pourrait impliquer l'exécution plusieurs autres commandes), serait plus lent.

En cas de doute, lancez un test ...

agc
la source
donc pour accélérer mon script bash, je dois les réécrire en bash ou ksh?
Kingofkech
@Kingofkech Il se peut que le code que vous avez écrit pour bash soit facilement un code ksh ou dash correct. Essayez de simplement changer l'interprète.
bli