Bonsoir
Je viens de faire un bench à la mano vite fait afin de tenter de casser certaines idées reçues.
J'ai pris pour cela une fonction nulle qui vérifie si un nombre est premier, un bon nombre premier (4012009) et j'ai comparé python 2.3.3, perl 5.8.3, c++ (gcc 3.3.3) et python2.3.3+psyco1.2 (avec la commande time)
Les résultats parlent d'eux même :
Perl :
real 0m2.224s
user 0m1.644s
sys 0m0.015s
Python :
real 0m3.491s
user 0m2.436s
sys 0m0.186s
cpp :
real 0m0.207s
user 0m0.154s
sys 0m0.002s
python+psyco :
real 0m0.391s
user 0m0.235s
sys 0m0.010s
Face à ces résultats, plusieurs questions me taraudent :
- python est très lent sans psyco : c'est pas nouveau, mais c'est du à quoi ???
- python+psyco est très très rapide :
= y a-t-il des défauts provoqués par psyco (conso mémoire, CPU...) ?
= du code python risque-t-il de ne pas s'exécuter à cause de python ?
= pourquoi psyco n'est pas dans la lib python standard ?
= pourquoi continue-t-on à dire "python est lent" tout court alors qu'il peut être presque aussi rapide que le C++ à l'aide de psyco?
Merci de répondre à ces questions sans trop troller
PS : c'est qu'un benchmark, je sais
# sources
Posté par tgl . Évalué à 4.
Merci d'avance.
[^] # Re: sources
Posté par Pinaraf . Évalué à 2.
J'ai essayé d'avoir une version python et une version perl très proches, alors que par méconnaissance la version C++ est plus éloignée.
Bon, je viens de m'apercevoir que ma fonction is_premier déconnait : 4012009 n'est pas premier ! J'avais fait boulette sur la fonction modulo, enfin c'est pas grave ça change pas les résultats :)
Version C++
#include
bool is_premier (int nombre) {
int i;
for (i=1 ; i < nombre ; i++) {
if (nombre % i == 0)
return false;
}
return true;
}
int main (int argc, char **argv) {
if (is_premier(4012009)) std::cout << "4012009 est premier\n";
else std::cout << "4012009 n'est pas premier\n";
}
Version Perl
#!/usr/bin/env perl
sub is_premier {
my ($nombre) = @_;
my $i;
foreach $i (1..($nombre-1)) {
if ($nombre%$i == 0) {
return 0;
}
}
return 1;
}
if (is_premier(4012009)) {
print "4012009 est premier\n"
} else {
print "4012009 n'est pas premier\n"
}
Version Python
#!/usr/bin/env python
import psyco #à commenter pour
psyco.full() # désactiver psyco
def is_premier(nombre):
for i in range(1, nombre):
if (nombre%i == 0):
return 0
return 1
if (is_premier (4012009)):
print "4012009 est premier"
else:
print "4012009 n'est pas premier"
Ce sera tout ?
[^] # Re: sources
Posté par Pascal Terjan (site web personnel) . Évalué à 3.
pascal@jc:~/b$ time ruby test.rb
4012009 n'est pas premier
0.01user 0.00system 0:00.00elapsed 111%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (262major+146minor)pagefaults 0swaps
pascal@jc:~/b$ time perl test.pl
4012009 n'est pas premier
0.01user 0.00system 0:00.00elapsed 200%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (352major+61minor)pagefaults 0swaps
pascal@jc:~/b$ time python test.py
4012009 n'est pas premier
0.40user 0.21system 0:00.69elapsed 87%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (487major+16039minor)pagefaults 0swaps
Le code ruby :
def is_premier(nombre)
(2..nombre-1).each { |i|
return false if (nombre%i == 0)
}
return true;
end
if (is_premier(4012009))
print "4012009 est premier\n"
else
print "4012009 n'est pas premier\n"
end
[^] # Re: sources
Posté par Misc (site web personnel) . Évalué à 3.
En prenant xrange, j'ai ça :
/tmp $ time python p.py
4012009 n'est pas premier
0.99user 0.40system 0:02.88elapsed 48%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+16442minor)pagefaults 0swaps
/tmp $ perl -pi 's/range/xrange/' p.py
/tmp $ time python p.py
4012009 n'est pas premier
0.05user 0.01system 0:00.07elapsed 89%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+680minor)pagefaults 0swaps
/tmp $ grep psyco p.py
/tmp $ ( echo 'import psyco' ; echo "psyco.full()" ; cat p.py ) > p2.py
/tmp $ time python p2.py
4012009 n'est pas premier
0.06user 0.02system 0:00.29elapsed 30%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (2major+838minor)pagefaults 0swaps
/tmp $ time ruby p.rb
4012009 n'est pas premier
0.02user 0.00system 0:00.86elapsed 3%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (14major+380minor)pagefaults 0swaps
/tmp $ time perl p.pl
4012009 n'est pas premier
0.00user 0.00system 0:00.01elapsed 63%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+411minor)pagefaults 0swaps
Ou on voit que le fait de compiler avec psyco a un impact non négligeable sur le bench, quand on utilise xrange. Il faudrait donc le faire tourner sur un nombre bien plus grand ( et surtout premier ).
[^] # Re: sources
Posté par gc (site web personnel) . Évalué à 2.
pour avoir un bench correct, se renseigner auprès de nombreux sites qui l'ont déjà fait de manière sérieuse.
[^] # Re: sources
Posté par Pinaraf . Évalué à 1.
Pourrais tu aussi expliquer en quoi ce bench mesure le startup time ? Et pourquoi python + psyco est mille fois plus rapide que python seul ? Si y'a que le startup time, alors psyco est magique !
Merci d'avance
[^] # Re: sources
Posté par gc (site web personnel) . Évalué à 4.
Un bench souvent considéré comme une bonne référence (mais les données sont anciennes) :
http://www.bagley.org/~doug/shootout/index3.shtml(...)
Je n'ai jamais regardé les détails de la mesure des valeurs sur ce test, cependant.
[^] # Re: sources
Posté par Julien Portalier . Évalué à 2.
- Regarder l'heure qu'il est (debut)
- Lancer is_premier() sur n nombres, avec n un nombre suffisamment grand.
- Re-regarder l'heure qu'il est (fin)
- Faire la différence entre debut et fin et diviser le tout par n
Hop, on a le temps de calcul moyen pour la recherche d'un nombre premier (avec les temps d'appel de fct°, de passage de paramètres, etc). Et ce sans passer par la phase de précompilation, de compilation JIT, de lancement de l'application, etc. Là, le bench serait plus intéressant et réaliste.
D'ailleurs j'aimerai bien savoir ce que ça donne...
[^] # Re: sources optimise
Posté par ogotail . Évalué à 1.
Version Python
#!/usr/bin/env python
import psyco #à commenter pour
psyco.full() # désactiver psyco
def is_premier(nombre):
for i in range(1, nombre/2): # pas besoin de chercher plus loin
if (nombre%i == 0):
return 0
return 1
if (is_premier (4012009)):
print "4012009 est premier"
else:
print "4012009 n'est pas premier"
ok je ---> []
[^] # Re: sources optimise
Posté par Pinaraf . Évalué à 0.
def is_premier (nombre):
if nombre in [2,3,5,7]:
return 0
for i in range(9,nombre/2,2): # pourquoi vérifier les nombres pairs ?
if (nombre%i == 0):
return 0
return 1
[^] # Re: sources optimise
Posté par ogotail . Évalué à 1.
def is_premier (nombre):
if nombre in [2,3,5,7]:
return 0
for i in range(9,nombre,2): # pourquoi vérifier les nombres pairs ?
if i > nombre/i : # pourquoi aller plus loin (= range max racine_carree(nombre) )
return 0
if (nombre%i == 0):
return 0
return 1
[^] # Re: sources optimise
Posté par Pinaraf . Évalué à 1.
def is_premier (nombre):
if nombre in [2,3,5,7]:
return 0
for i in range(9,int(sqrt(nombre)+1),2):
if (nombre%i == 0):
return 0
return 1
[^] # Re: sources optimise
Posté par ogotail . Évalué à 1.
# Psyco
Posté par Amand Tihon (site web personnel) . Évalué à 4.
python est très lent sans psyco : c'est pas nouveau, mais c'est du à quoi ???
100% interprété.
Tout objet. faire « x = 0.2 * 0.7 » revient à instancier 3 floats, etc...
Le code python est compilé en bytecode avant interprétation, mais c'est tout. Psyco compile ce qu'il peut en natif.
y a-t-il des défauts provoqués par psyco (conso mémoire, CPU...) ?
Pas à ma connaissance. Peut être la lecture du site de psyco pourrait-elle t'en dire plus à ce sujet ?
du code python risque-t-il de ne pas s'exécuter à cause de python ?
Je présume que tu voulais dire "à cause de psyco". Normalement, non. Si psyco ne peut pas compiler un truc, il ne le compile pas.
pourquoi psyco n'est pas dans la lib python standard ?
Très facile : c'est un gros hack pas portable. Ca ne fonctionne que sur x86, à ma connaissance.
pourquoi continue-t-on à dire "python est lent" [...] ?
Peut-être parce que sur un bench comme celui-ci, sans psyco, il est lent ? :)
Personnellement, je ne trouve pas que la "lenteur" (toute relative) de python soit rédhibitoire. Une interface en pyqt/pykde/wxpython/pygtk est bigrement plus réactive qu'une interface en java-gtk-machin, même sans psyco.
J'utilise maintenant le Python pour l'énorme majorité de mes développements, et j'en suis pleinement satisfait (ne me faites pas dire ce que je n'ai pas dit, il n'est pas parfait, ni meilleur que les autres langages).
Note aussi que ton bench semble particulièrement adapté à psyco...
# A propos de Psyco
Posté par _alex . Évalué à 3.
En gros c'est de la compilation JIT mais la ou c'est très fort, ce que pour un même code, plusieurs versions compilées sont générées en fonction de paramètres d'entrés. Donc si les paramèters le permettent, la fonction est bien optimisée.
cf les drawback :
- ca mange de la RAM (toutes les versions, les différents état etc...)
- ca marche uniquement sur x86
- "here are some subtle semantic differences (i.e. bugs)"
[^] # Re: A propos de Psyco
Posté par Julien Portalier . Évalué à 2.
Sinon, j'ajoute encore un drawback : le programme devient relativement long à démarrer (ben oui, faut compiler). Surtout avec full() qui compile tout et pas en fonction des besoins. Dans mes applications, j'utilise surtout profile() (comme c'est recommandé), et qui ne compile que ce qu'il est vraiment nécessaire de compiler.
J'ajoute un avantage : la possibilité de définir les fonctions à compiler, ou à partir de quel niveau compiler une fct°, etc.
# Correction du code python
Posté par Julien Portalier . Évalué à 2.
[^] # Re: Correction du code python
Posté par Pascal Terjan (site web personnel) . Évalué à 2.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.