8
votes

À Perl, pourquoi les matrices nouées sont-elles si lentes?

Dans mes tests, j'ai remarqué que l'itération des tableaux liés est au mieux moitié aussi rapide que l'utilisation des méthodes d'accesseur interne ( Fetch et extraire ). Le repère suivant montre le problème: xxx

avec une taille de matrice de 1000, le repère de référence: xxx

J'ai omis les autres courses Parce que la taille de la matrice ne produit pas de changement significatif dans les vitesses relatives.

méthode est bien sûr le plus rapide, car il ne vérifie pas la taille de la matrice sur chaque itération, toutefois méthod_while et méthody_while2 semble fonctionner sur le tableau fixé de la même manière que le pour boucle, mais même le code Méthode_whIII2 est deux fois plus rapide que la matrice liée.

Ajout même de la localisation de $ _ et affectation aliasée à méthod_while2 dans Méthode_wwile3 résulte en 66% d'exécution plus rapide que la matrice liée.

Quel travail supplémentaire se produit dans la boucle pour qui ne se produit pas dans méthode_while3 < / code>? Y a-t-il un moyen d'améliorer la vitesse de la matrice liée?


1 commentaires

méthode serait encore plus rapide si Perl peut optimiser pour 0. y en ne construisant pas pré-construire un tableau de longueur Y. L'optimiseur est facilement dupe si y n'est pas un scalaire simple . Essayez ma taille $ = $ like-> aller-gretsize - 1; $ x + = $ attaché-> récupérez ($ _) pour 0. $ Taille et voyez si cela fonctionne mieux.


3 Réponses :


7
votes

Chaque fois que vous utilisez la matrice liée, il doit rechercher l'objet attaché, puis rechercher les méthodes, puis les invoquer. Avec vos autres versions, vous faites tout ou partie de cette recherche soit au moment de la compilation, soit une fois avant la boucle au lieu de chaque accès.

(la comparaison des vitesses entre méthode et l'autre méthode _ * est un bon exemple de ceci, en passant: vous voyez la dépense de le faire extraire , même si l'objet attaché a déjà levé les yeux. Maintenant, appliquez maintenant ce coût à chaque opération qui touche le tableau.)


3 commentaires

Méthode_while3 ne prépache rien et semble faire tout ce que la boucle de foresach est, mais reste 66% plus rapide.


Je pense que cela fait de la mise en cache: avec le code de bouclage explicite, l'optimiseur de Perl peut voir ce qui se passe et même étant donné que le extraire ne peut pas être soulevé de la boucle (puisqu'il ne peut pas Dites que vous n'ayez pas accès à une ressource externe dont la taille peut changer de manière dynamique), il peut voir que l'appel lié ​​ doit être effectué une seule fois. Je ne pense pas que cela se produise pour pour @ $ array car les internes sont cachés à partir de vous et de l'optimiseur. (L'optimisation au Perl 5 est ... difficile, de la mettre légèrement, de sorte que dans de nombreux cas, cela n'essaie même pas.) BTW, il s'agit de la version très perl dépendante.


J'ai remplacé le (@ $ tableau) -> méthode avec My $ get_tied = sous {attaché (@ {$ _ [0]})}; puis $ get_tied -> ($ array) -> Méthode pour contrecarrer toute sorte de mise en cache et même ajouter ces deux appels de sous-programme supplémentaires à chaque itération est toujours de 25% plus rapide que la boucle pour :(



3
votes

Dans la référence, vous faites

tied_rvalue => sub {
    my $x = 0;
    $x += $_ for @$array;
    $x == $sum or die $x
},
tied_lvalue => sub {
    my $x = 0;
    $x += $array->[$_] for 0 .. $tied->FETCHSIZE - 1;
    $x == $sum or die $x
},

100:
                 Rate tied_rvalue method_while3 tied_lvalue method_while2 method_while method
tied_rvalue    3333/s          --          -33%        -36%          -50%         -58%   -77%
method_while3  4998/s         50%            --         -4%          -25%         -36%   -66%
tied_lvalue    5184/s         56%            4%          --          -23%         -34%   -65%
method_while2  6699/s        101%           34%         29%            --         -15%   -55%
method_while   7856/s        136%           57%         52%           17%           --   -47%
method        14747/s        342%          195%        184%          120%          88%     --


1 commentaires

+1, intéressant, je n'avais pas envisagé que Perl a besoin d'appliquer la magie à la variable pour gérer un appel possible ultérieur à Store



3
votes

Il est à noter que local est très lent qui représente une partie de la perte de performance dans la méthode_while3 vs les autres points de repère de méthode. Il fait également une entrée de bloc et une sortie qui comporte des coûts.

Même si Method_while3 est équivalent par programmation à la relève pour x..y , Perl peut optimiser la boucle mieux que possible. En règle générale, plus vous faites du code à l'intérieur de Perl, plus votre code sera plus rapide.


0 commentaires