web-dev-qa-db-fra.com

La langue Julia est-elle vraiment aussi rapide qu'elle le prétend?

Après cet article j'ai décidé de comparer Julia à GNU Octave et les résultats étaient incompatibles avec les accélérations illustrées dans julialang.org .

J'ai compilé Julia et GNU Octave avec CXXFLAGS='-std=c++11 -O3', les résultats que j'ai obtenus:

GNU Octave

a=0.9999;

tic;y=a.^(1:10000);toc
Elapsed time is 0.000159025 seconds.

tic;y=a.^(1:10000);toc
Elapsed time is 0.000162125 seconds.

tic;y=a.^(1:10000);toc
Elapsed time is 0.000159979 seconds.

-

tic;y=cumprod(ones(1,10000)*a);toc
Elapsed time is 0.000280142 seconds.

tic;y=cumprod(ones(1,10000)*a);toc
Elapsed time is 0.000280142 seconds.

tic;y=cumprod(ones(1,10000)*a);toc
Elapsed time is 0.000277996 seconds.

Julia

tic();y=a.^(1:10000);toc()
elapsed time: 0.003486508 seconds

tic();y=a.^(1:10000);toc()
elapsed time: 0.003909662 seconds

tic();y=a.^(1:10000);toc()
elapsed time: 0.003465313 seconds

-

tic();y=cumprod(ones(1,10000)*a);toc()
elapsed time: 0.001692931 seconds

tic();y=cumprod(ones(1,10000)*a);toc()
elapsed time: 0.001690245 seconds

tic();y=cumprod(ones(1,10000)*a);toc()
elapsed time: 0.001689241 seconds

Quelqu'un pourrait-il expliquer pourquoi Julia est plus lente que GNU Octave avec ces opérations de base? Après réchauffé, il devrait appeler LAPACK/BLAS sans surcharge, non?

MODIFIER:

Comme expliqué dans les commentaires et réponses, le code ci-dessus n'est pas une bonne référence ni illustre les avantages de l'utilisation du langage dans une application réelle. Je pensais à Julia comme un "Octave/MATLAB" plus rapide, mais c'est bien plus que cela. C'est un grand pas vers productif, un calcul scientifique performant. En utilisant Julia, j'ai pu 1) surpasser les logiciels de mon domaine de recherche écrits en Fortran et C++, et 2) fournir aux utilisateurs une API beaucoup plus agréable.

40
juliohm

Opérations vectorisées comme .^ sont exactement le genre de choses dans lesquelles Octave est bon car elles sont en fait entièrement implémentées dans du code C spécialisé. Quelque part dans le code qui est compilé lors de la construction d'Octave, il existe une fonction C qui calcule .^ pour un double et un tableau de doubles - c'est ce que vous planifiez vraiment ici, et c'est rapide parce que c'est écrit dans C. Julia's .^, par contre, s'écrit en Julia:

Julia> a = 0.9999;

Julia> @which a.^(1:10000)
.^(x::Number,r::Ranges{T}) at range.jl:327

Cette définition se compose de ceci:

.^(x::Number, r::Ranges) = [ x^y for y=r ]

Il utilise une compréhension de tableau unidimensionnel pour élever x à chaque valeur y dans la plage r, renvoyant le résultat sous forme de vecteur.

Edward Garson a tout à fait raison de ne pas utiliser les globaux pour des performances optimales dans Julia. La raison en est que le compilateur ne peut pas très bien raisonner sur les types de globaux car ils peuvent changer à tout moment où l'exécution quitte la portée actuelle. Quitter la portée actuelle ne semble pas se produire souvent, mais dans Julia, même les choses de base comme l'indexation dans un tableau ou l'ajout de deux entiers sont en fait des appels de méthode et quittent ainsi la portée actuelle. Dans le code de cette question, cependant, tout le temps est passé à l'intérieur du .^, donc le fait que a est un global n'a pas vraiment d'importance:

Julia> @elapsed a.^(1:10000)
0.000809698

Julia> let a = 0.9999;
         @elapsed a.^(1:10000)
       end
0.000804208

En fin de compte, si tout ce que vous faites est d'appeler des opérations vectorisées sur des tableaux à virgule flottante, Octave est très bien. Cependant, ce n'est souvent pas réellement où la plupart du temps est passé, même dans des langages dynamiques de haut niveau. Si vous vous retrouvez à vouloir parcourir un tableau avec une boucle for, opérant sur chaque élément avec une arithmétique scalaire, vous constaterez qu'Octave est assez lent dans ce genre de choses - souvent des milliers de fois plus lentement que le code C ou Julia. la même chose. L'écriture de boucles dans Julia, d'autre part, est une chose parfaitement raisonnable à faire - en fait, tout notre code de tri est écrit en Julia et est comparable à C en termes de performances. Il existe également de nombreuses autres raisons d'utiliser Julia qui ne sont pas liées aux performances. En tant que clone de Matlab, Octave hérite de nombreux problèmes de conception de Matlab, et ne s'en sort pas très bien comme langage de programmation à usage général. Vous ne voudriez pas, par exemple, écrire un service web dans Octave ou Matlab, mais c'est assez facile de le faire dans Julia.

62
StefanKarpinski

Vous utilisez des variables globales qui sont un piège de performances dans Julia.

Le problème est que les globaux peuvent potentiellement changer de type chaque fois que votre code appelle une fonction anthère. Par conséquent, le compilateur doit générer du code extrêmement lent qui ne peut faire aucune hypothèse sur les types de variables globales utilisées.

De simples modifications de votre code en ligne avec https://docs.julialang.org/en/stable/manual/performance-tips/ devraient donner des résultats plus satisfaisants.

14
EdwardGarson