Comparaison de vitesse entre Python et Julia

9

J'ai essayé de comparer ces deux extraits et de voir combien d'itérations pouvaient être effectuées en une seconde. Il s'avère que Julia réalise 2,5 millions d'itérations alors que Python 4 millions. Julia n'est-elle pas censée être plus rapide. Ou peut-être que ces deux extraits ne sont pas équivalents?

Python:

t1 = time.time()
i = 0
while True:
    i += 1
    if time.time() - t1 >= 1:
        break

Julia:

function f()
    i = 0
    t1 = now()
    while true
        i += 1
        if now() - t1 >= Base.Dates.Millisecond(1000)
            break
        end
    end
    return i
end
Michas
la source
4
Je ne sais pas comment Julia fonctionne, mais il semble que vous devez construire un nouvel objet pour chaque comparaison, tandis que Python fait de simples comparaisons entières.
chepner
1
Veuillez également noter qu'il s'agit d'une comparaison de la vitesse de l'homme pauvre, n'est-ce pas? De nos jours, vous pouvez faire fonctionner Python et Julia à peu près à la même vitesse avec la bonne quantité de motivation (aux deux extrémités). Si vous faites cela pour choisir l'une ou l'autre des langues, regardez dans laquelle il vous sera plus facile de penser. Vous pouvez optimiser cela plus tard, lorsque vous en avez réellement besoin.
norok2
@ norok2 C'est vrai pour certains codes mais pas pour d'autres. Si vous êtes en mesure de transformer le code Python en un appel à une fonction de bibliothèque écrite dans un langage rapide, ou s'il est pris en charge par numba, ou quelque chose de similaire, alors peut-être, mais sinon Python est beaucoup plus lent.
DNF
@DNF Il y a des choses où Python est plus rapide et d'autres où Julia est plus rapide. Je suis sûr que vous pouvez trouver des exemples des deux. Il est excessivement ignoré de l'image complète de dire que Python est "significativement" (quoi que cela puisse signifier) ​​plus lent simplement en raison du bouclage explicite relativement coûteux et des appels de fonction. Bien sûr, si c'est votre cheval de bataille, peut-être que vous êtes mieux avec Julia. Cependant, si vous utilisez les bons outils, vous pouvez obtenir tout aussi rapidement en Python. Vaut-il la peine d'apprendre ces outils ou vaut-il mieux apprendre une autre langue? C'est dur à dire.
norok2
1
J'utilise les deux langues, et bien qu'il y ait «quelques» exemples des deux plus rapides, l'équilibre est considérablement d'un côté. C'est simplement une conséquence de Python étant interprété et se concentrant à peine sur les performances, tandis que Julia se concentre fortement sur les performances. C'est en fait un peu comme dire que Python est aussi rapide que C. Ce serait très étrange s'il n'y avait pas de différence significative, et cela minerait une grande partie de l'objectif de Julia.
DNF

Réponses:

9

C'est une sorte de comparaison de performances étrange car généralement on mesure le temps qu'il faut pour calculer quelque chose de substantiel, plutôt que de voir combien d'itérations triviales on peut faire dans un certain laps de temps. J'ai eu du mal à faire fonctionner vos codes Python et Julia, j'ai donc modifié le code Julia pour qu'il fonctionne et je n'ai tout simplement pas exécuté le code Python. Comme l'a noté @chepner dans un commentaire, l'utilisation now()et la comparaison de temps avec des DateTimeobjets sont assez coûteuses. La time.time()fonction Python renvoie simplement une valeur à virgule flottante. En fait, il y a une fonction Julia appelée time()qui fait exactement la même chose:

julia> time()
1.587648091474481e9

Voici le timing de votre f()fonction d' origine (modifiée pour fonctionner) sur mon système:

julia> using Dates

julia> function f()
           i = 0
           t1 = now()
           while true
               i += 1
               if now() - t1 >= Millisecond(1000)
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
4943739

Il a fait près de 5 millions d'itérations avant la fin du temps. Comme je l'ai dit, je n'ai pas pu faire fonctionner votre code Python sur mon système sans bidouiller (ce que je n'ai pas pris la peine de faire). Mais voici une version de f()cette utilisation à la time()place, que j'appellerai avec imagination g():

julia> function g()
           i = 0
           t1 = time()
           while true
               i += 1
               if time() - t1 >= 1
                   break
               end
           end
           return i
       end
g (generic function with 1 method)

julia> g()
36087637

Cette version a fait 36 ​​millions d'itérations. Donc je suppose que Julia est plus rapide à boucler? Yay! Eh bien, en fait, le travail principal dans cette boucle est les appels à time()donc ... Julia est plus rapide à générer beaucoup d' time()appels!

Pourquoi est-il étrange de chronométrer cela? Comme je l'ai dit, la plupart du travail réel ici appelle time(). Le reste de la boucle ne fait vraiment rien. Dans un langage compilé optimisé, si le compilateur voit une boucle qui ne fait rien, il l'éliminera complètement. Par exemple:

julia> function h()
           t = 0
           for i = 1:100_000_000
               t += i
           end
           return t
       end
h (generic function with 1 method)

julia> h()
5000000050000000

julia> @time h()
  0.000000 seconds
5000000050000000    

Woah, zéro seconde! Comment est-ce possible? Eh bien, regardons le code LLVM (un peu comme le code machine mais pour une machine imaginaire qui est utilisée comme représentation intermédiaire), cela diminue pour:

julia> @code_llvm h()

;  @ REPL[16]:1 within `h'
define i64 @julia_h_293() {
top:
;  @ REPL[16]:6 within `h'
  ret i64 5000000050000000
}

Le compilateur voit la boucle, découvre que le résultat est le même à chaque fois et renvoie simplement cette valeur constante au lieu d'exécuter réellement la boucle. Ce qui, bien sûr, ne prend aucun temps.

StefanKarpinski
la source
Ce sont les BogoMips des langages de programmation
norok2
1
C'est vrai, mais des bogomips sont utilisés pour mesurer le CPU, pas le langage de programmation. Mais bien sûr, c'est une chose que l'on peut mesurer.
StefanKarpinski
4

Vous voulez probablement utiliser la time_nsfonction dans Julia:

function f()
    i = 0
    t1 = time_ns()
    while true
        i += 1
        if time_ns() - t1 >= 10^9
            break
        end
    end
    return i
end

Sur mon ordinateur, il fonctionne 10 fois plus vite que Python.

Bogumił Kamiński
la source
4

Eh bien, ce n'est pas ce que j'observe sur mon système:

Python 3.7.7

Python 3.7.7 (default, Mar 26 2020, 15:48:22) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import time                                                                                                                                                       

In [2]: def f(): 
   ...:     t1 = time.time() 
   ...:     i = 0 
   ...:     while True: 
   ...:         i += 1 
   ...:         if time.time() - t1 >= 1: 
   ...:             return i 
   ...:                                                                                                                                                                   

In [3]: f()                                                                                                                                                               
Out[3]: 4676268


Julia 1.4.0:

julia> using Dates

julia> function f()
           i = 0
           t1 = now()
           while true
               i += 1
               if now() - t1 >= Dates.Millisecond(1000)
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
6339528

mais notez que simplement utiliser time(c'est-à-dire comparer des nombres simples) est encore plus rapide:

julia> function f()
           i = 0
           t1 = time()
           while true
               i += 1
               if time() - t1 >= 1
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
24742703
François Févotte
la source
ne devriez-vous pas utiliser time.perf_counter_ns()en Python?
norok2
L'utilisation de time.perf_counter_ns ne change rien (au moins sur mon système) pour ce benchmark. Je suppose que lorsque l'on mesure des différences de temps de l'ordre de 1 seconde, la précision de la mesure du temps n'a pas beaucoup d'importance. Seul le temps nécessaire pour prendre la mesure et comparer les objets résultants importe ici (ainsi que l'efficacité des boucles elles-mêmes).
François Févotte
Dans Julia, le temps de mesure est important - c'est pourquoi dans mon code, je time_nsne l' ai pas utilisé timecar il est alors 30% plus rapide.
Bogumił Kamiński