Je testais la vitesse de Bash et Python en exécutant une boucle 1 milliard de fois.
$ cat python.py
#!/bin/python
# python v3.5
i=0;
while i<=1000000000:
i=i+1;
Code Bash:
$ cat bash2.sh
#!/bin/bash
# bash v4.3
i=0
while [[ $i -le 1000000000 ]]
do
let i++
done
En utilisant la time
commande, j'ai découvert que le code Python ne prend que 48 secondes pour terminer tandis que le code Bash a pris plus d'une heure avant de tuer le script.
Pourquoi cela est-il ainsi? Je m'attendais à ce que Bash soit plus rapide. Y a-t-il un problème avec mon script ou Bash est-il vraiment beaucoup plus lent avec ce script?
echo echo hello >> $0
, et l'exécuter.Réponses:
Il s'agit d'un bogue connu dans bash; voir la page de manuel et rechercher "BUGS":
;)
Pour une excellente introduction aux différences conceptuelles entre les scripts shell et d'autres langages de programmation, je recommande fortement la lecture:
Les extraits les plus pertinents:
N'utilisez pas de grandes boucles dans les scripts shell.
la source
Les boucles de shell sont lentes et les bash sont les plus lentes. Les obus ne sont pas destinés à effectuer un travail lourd en boucles. Les shells sont destinés à lancer quelques processus externes optimisés sur des lots de données.
Quoi qu'il en soit, j'étais curieux de savoir comment les boucles shell se comparent, j'ai donc fait un petit point de repère:
( Détails:
)
Les résultats (abrégés) (temps par itération) sont:
D'après les résultats:
Si vous voulez une boucle de shell un peu plus rapide, alors si vous avez la
[[
syntaxe et que vous voulez une boucle de shell rapide, vous êtes dans un shell avancé et vous avez aussi la boucle for de type C. Utilisez alors la boucle C comme pour. Ils peuvent être environ 2 fois plus rapides que leswhile [
boucles dans la même coque.for (
boucle la plus rapide à environ 2,7 µs par itérationwhile [
boucle la plus rapide à environ 5,8 µs par itérationC pour les boucles peut être de 3 à 4 décimales plus rapide. (J'ai entendu les Torvalds adorer C).
La boucle C optimisée est 56500 fois plus rapide que la
while [
boucle de bash (la boucle de shell la plus lente) et 6750 fois plus rapide que lafor (
boucle de ksh (la boucle de shell la plus rapide).Encore une fois, la lenteur des shells ne devrait pas avoir beaucoup d'importance, car le modèle typique des shells consiste à se décharger sur quelques processus de programmes externes optimisés.
Avec ce modèle, les shells facilitent souvent l'écriture de scripts avec des performances supérieures aux scripts python (la dernière fois que j'ai vérifié, créer des pipelines de processus en python était plutôt maladroit).
Une autre chose à considérer est le temps de démarrage.
prend 30 à 40 ms sur mon PC alors que les obus prennent environ 3 ms. Si vous lancez beaucoup de scripts, cela s'ajoute rapidement et vous pouvez faire beaucoup dans les 27 à 37 ms supplémentaires que python prend juste pour démarrer. Les petits scripts peuvent être terminés plusieurs fois au cours de cette période.
(NodeJs est probablement le pire runtime de script dans ce département car il faut environ 100 ms pour démarrer (même si une fois qu'il a démarré, vous auriez du mal à trouver un meilleur interprète parmi les langages de script)).
la source
ksh88
, AT & Tksh93
,pdksh
,mksh
...) comme il y a beaucoup de variations entre eux. Pourbash
, vous souhaiterez peut-être spécifier la version. Il a fait quelques progrès ces derniers temps (cela s'applique également aux autres obus).from subprocess import *; p1=Popen(['echo', 'something'], stdout=PIPE); p2 = Popen(['grep', 'pattern'], stdin=p1.stdout, stdout=PIPE); Popen(['wc', '-c'], stdin=PIPE)
. C'est en effet maladroit, mais il ne devrait pas être difficile de coder unepipeline
fonction qui le fait pour vous pour un certain nombre de processus, ce qui entraînepipeline(['echo', 'something'], ['grep', 'patter'], ['wc', '-c'])
.J'ai fait un peu de test, et sur mon système j'ai exécuté ce qui suit - aucun n'a accéléré l'ordre de grandeur qui serait nécessaire pour être compétitif, mais vous pouvez le faire plus rapidement:
Test 1: 18,233s
test2: 20.45s
test3: 17,64 s
test4: 26.69s
test5: 12.79s
La partie importante dans ce dernier est l'export LC_ALL = C. J'ai constaté que de nombreuses opérations bash se terminent beaucoup plus rapidement si elles sont utilisées, en particulier toute fonction d'expression régulière. Il montre également une syntaxe non documentée pour utiliser le {} et le: comme no-op.
la source
[[
est tellement plus rapide que[
. Je ne savais pas que LC_ALL = C (BTW vous n'avez pas besoin de l'exporter) a fait une différence.[[
est un bash intégré, et[
est vraiment/bin/[
, ce qui est le même que/bin/test
- un programme externe. C'est pourquoi thay est plus lent.[
est une fonction intégrée dans tous les shells courants (essayeztype [
). Le programme externe est pour la plupart inutilisé maintenant.Un shell est efficace si vous l'utilisez pour ce pour quoi il a été conçu (bien que l'efficacité soit rarement ce que vous recherchez dans un shell).
Un shell est un interpréteur de ligne de commande, il est conçu pour exécuter des commandes et les faire coopérer à une tâche.
Si vous voulez compter jusqu'à 1000000000, vous invoquez un (une) commande à compter, comme
seq
,bc
,awk
oupython
/perl
... Exécution 1000000000[[...]]
commandes et 1000000000let
commandes est lié à être terriblement inefficace, en particulier avec cebash
qui est le plus lent shell de tous.À cet égard, un shell sera beaucoup plus rapide:
Bien sûr, la plupart du travail est fait par les commandes que le shell appelle, comme il se doit.
Maintenant, vous pouvez bien sûr faire de même avec
python
:Mais ce n'est pas vraiment comme ça que vous feriez les choses,
python
carpython
c'est principalement un langage de programmation, pas un interpréteur de ligne de commande.Notez que vous pourriez faire:
Mais,
python
serait en fait appeler un shell pour interpréter cette ligne de commande!la source
Réponse: Bash est beaucoup plus lent que Python.
Un petit exemple est dans la publication de blog Performance de plusieurs langues .
la source
Rien n'est faux (sauf vos attentes) car python est vraiment assez rapide pour un langage non compilé, voir https://wiki.python.org/moin/PythonSpeed
la source
Mis à part les commentaires, vous pouvez optimiser un peu le code , par exemple
Ce code devrait prendre un peu moins de temps.
Mais évidemment pas assez rapide pour être réellement utilisable.
la source
J'ai remarqué une différence dramatique dans bash par rapport à l'utilisation d'expressions logiques "while" et "until":
Non pas que cela soit vraiment extrêmement pertinent pour la question, à part que parfois de petites différences font une grande différence, même si nous nous attendons à ce qu'elles soient équivalentes.
la source
((i==900000))
.=
pour l'affectation. Cela reviendra immédiatement. Aucune boucle n'aura lieu.