5
votes

Question de l'optimiseur Perl: le compilateur perl optimisera-t-il toutes ces variables temporaires?

J'ai un morceau d'arithmétique assez simple, mais pour la lisibilité et l'exactitude, je l'ai développé dans un tas de variables temporaires. Il est plus facile de lire, de modifier et d'examiner des parties partielles de l'expression.

Ma question est la suivante: ce code prendra-t-il un temps d'exécution simplement parce qu'il est développé? Je ne sais pas comment fonctionne le compilateur perl, mais en 'C', ou autre, ces variables supplémentaires (pas tout à fait) seraient optimisées dès leur disparition.

my $targetBasis = $$s{"basis"} * $nextBasisPct;
my $dollarsHeld = $$s{"basis"} * $$s{"held"};
my $targetDollars = $dollarsHeld + $opt{"buyDollars"};
my $targetShares = $targetDollars / $targetBasis;
my $newShares = $targetShares - $$s{"held"};
my $targetPrice = $opt{"buyDollars"} / $newShares;

Merci.

-E

Je viens de terminer cette extension à partir d'une doublure d'aspect méchant, pour constater que c'était correct. Je préfère ne pas le rendre illisible s'il n'y a aucune raison de le faire.


0 commentaires

3 Réponses :


9
votes

Non.

Ce qui suit La version compilée du programme

use strict;
my ($s, %opt, $targetBasis);

Notez que j'ai d'abord ajouté ce qui suit au programme:

$ perl -MO=Concise,-exec a.pl
1  <0> enter
2  <;> nextstate(main 2 a.pl:2) v:*,&,{,x*,x&,x$,$
3  <0> padrange[$s:2,8; %opt:2,8; $targetBasis:2,8] vM/LVINTRO,range=3
4  <;> nextstate(main 3 a.pl:3) v:*,&,{,x*,x&,x$,$
5  <+> multideref($s->{"basis"}) sK/STRICT
6  <+> multideref($s->{"held"}) sK/STRICT
7  <2> multiply[t5] sK/2
8  <0> padsv[$dollarsHeld:3,8] sRM*/LVINTRO
9  <2> sassign vKS/2
a  <;> nextstate(main 4 a.pl:4) v:*,&,{,x*,x&,x$,$
b  <0> padsv[$dollarsHeld:3,8] s
c  <+> multideref($opt{"buyDollars"}) sK
d  <2> add[t7] sK/2
e  <0> padsv[$targetDollars:4,8] sRM*/LVINTRO
f  <2> sassign vKS/2
g  <;> nextstate(main 5 a.pl:5) v:*,&,{,x*,x&,x$,$
h  <0> padsv[$targetDollars:4,8] s
i  <0> padsv[$targetBasis:2,8] s
j  <2> divide[t9] sK/2
k  <0> padsv[$targetShares:5,8] sRM*/LVINTRO
l  <2> sassign vKS/2
m  <;> nextstate(main 6 a.pl:6) v:*,&,{,x*,x&,x$,$
n  <0> padsv[$targetShares:5,8] s
o  <+> multideref($s->{"held"}) sK/STRICT
p  <2> subtract[t11] sK/2
q  <0> padsv[$newShares:6,8] sRM*/LVINTRO
r  <2> sassign vKS/2
s  <;> nextstate(main 7 a.pl:7) v:*,&,{,x*,x&,x$,$
t  <+> multideref($opt{"buyDollars"}) sK
u  <0> padsv[$newShares:6,8] s
v  <2> divide[t13] sK/2
w  <0> padsv[$targetPrice:7,8] sRM*/LVINTRO
x  <2> sassign vKS/2
y  <@> leave[1 ref] vKP/REFC
a.pl syntax OK

Optimiser les variables éviterait de copier une valeur dedans, mais copier un scalaire numérique dans un autre est très bon marché.

Je laisserais le code dans sa forme lisible. La lisibilité est bien plus importante que de gagner quelques nanosecondes.


3 commentaires

Mec, vous battez 1.000 cette semaine. Merci! Je suis d'accord sur la lisibilité. Je pense que j'allais le laisser de toute façon dans le cas où je voudrais inspecter les sous-expressions pour d'autres raisons. C'est génial d'apprendre comment obtenir la sortie pour enquêter sur cela. Un jour, j'apprendrai à le lire.


C'est ce avec quoi j'ai commencé. my $ targetPrice = $ opt {"buyDollars"} / (((($$ s {"base"} * $$ s {"hold"}) + $ opt {"buyDo‌ llars"}) / $ targetBasi‌ s) - $$ s {"hold"}); . J'aurais dû mettre cela dans la publication originale.


padrange / padsv sont des recherches de variables lexicales ( my ). LVINTRO signifie que c'est le mon lui-même. multideref est un nouvel opérateur qui englobe d'autres opérateurs, y compris les recherches de variables lexicales) pour plus d'efficacité.



5
votes

En général, Perl n'optimise jamais les variables, seulement les expressions constantes, car celles-ci sont connues pendant la phase d'analyse et de compilation, alors que l'affectation des variables se produit à l'exécution. Considérez que n'importe laquelle de ces variables pourrait être réutilisée plus tard dans la portée, ou qu'une référence à elles pourrait être prise par quelque chose et utilisée ailleurs. L'analyseur Perl fonctionne de manière séquentielle, ce qui serait vraiment difficile à expliquer.

En ce qui concerne vos préoccupations, à moins que vous n'écriviez du code avec une exigence en temps réel (pourquoi utiliser Perl pour cela?) ou que vous exécutiez ce code en boucle des millions de fois, la surcharge de la déclaration de variable n'est pas quelque chose à être préoccupé par. Les sous-appels sont légèrement plus visibles, les appels de méthode plus, mais les algorithmes inefficaces éclipsent ces préoccupations. En cas de doute, comparez.


3 commentaires

Bonnes informations sur la nature séquentielle de l'analyseur. Merci. Quant à «Pourquoi utiliseriez-vous perl pour cela?», Je dirais que c'est un langage très expressif. Si j'ai besoin d'une exécution rapide, j'utilise «C». Si j'ai besoin d'un temps de développement rapide, j'utilise perl. Si j'ai besoin d'une très bonne vérification de type, j'utilise Java ou C ++. Je cours sur des millions de lignes, mais pas si souvent que j'ai besoin de transpirer. Quelqu'un d'intelligent, dont le nom m'échappe, a fait écho à votre notion d'algorithmes inefficaces. "Il n'y a pas maintenant et il n'y aura jamais de langage dans lequel il est le moins difficile d'écrire un mauvais programme."


@ErikBennett Je ne vous demandais pas pourquoi vous utilisez Perl pour votre tâche, mais pourquoi vous (en général vous) l'utiliseriez pour des applications sensibles en temps réel, ce qui est une exigence très spécifique et difficile.


Je comprends. Ce n'est pas du temps réel.



5
votes

Vous avez déjà quelques bonnes réponses à votre question, mais je voulais ajouter quelques conseils pour améliorer la lisibilité de votre code.

  • Les clés de hachage n'ont pas besoin d'être entre guillemets sauf si elles contiennent des espaces. Ainsi, $ opt {"buyDollars"} , par exemple, peut s'écrire $ opt {buyDollars} .
  • Il semble que vous ayez une référence de hachage dans $ s . Le moyen standard d'accéder à une valeur à partir d'une référence de hachage est $ s -> {key} . Vous utilisez $$ s {key} qui fonctionne, mais qui sera très déroutant pour la plupart des gens qui liront votre code.

5 commentaires

Les deux bons points, et les deux révèlent dans une certaine mesure mon âge. La notation $ opt {"buyDollars"} est de m'assurer que je n'obtiens pas d'effets secondaires involontaires en utilisant un mot nu, comme une sous-référence, ou quelque chose. Cela m'est arrivé une fois et "a fait un gâchis". La notation $$ s {key} est antérieure à l'introduction récente de la notation $ hash -> {} . «Récent» étant un terme relatif.


@ErikBennett J'ai certainement fait la même chose pendant un moment en citant des clés de hachage. Mais avec une bonne compréhension du fonctionnement des citations de clé de hachage, vous pouvez être certain que cela ne se produira pas. Tant qu'il s'agit d'un identifiant valide, composé uniquement de lettres, chiffres et traits de soulignement, et ne commençant pas par un chiffre; alors il sera toujours traité comme une chaîne.


Je ne me souviens pas des détails, et ce n'est peut-être plus le cas, mais à un moment donné, j'ai fait quelque chose comme $ foo {delete} ou $ foo {sort} et ça n'a pas fait ce que je voulais. Cela peut avoir été perl3 ou perl4. C'était il y a quelque temps. Je vais lire l'état actuel des choses. Merci.


$ h -> {...} n'est récent par aucune mesure. Il est avec nous depuis au moins 5.6, qui est sorti il ​​y a près de 20 ans. La plupart des CPAN n'offrent la compatibilité qu'avec 5.8


Oui, c'est pourquoi j'ai dit plus tôt, «récent» est un terme relatif. Perl 5 était une véritable extension de Perl 4.