Comment puis-je accélérer mon programme Perl?

il s'agit en fait de deux questions, mais elles sont tellement similaires, et pour rester simple, j'ai pensé que je voudrais juste les rouler ensemble:

  • tout d'abord : étant donné un projet Perl établi, quels sont quelques moyens décents pour l'accélérer au-delà de l'optimisation simple en code?

  • Deuxièmement : lors de l'écriture d'un programme à partir de zéro en Perl, ce qui sont de bonnes façons de améliorer considérablement les performances?

pour la première question, imaginez que l'on vous remette un projet bien écrit et que vous devez améliorer vos performances, mais vous ne semblez pas pouvoir obtenir beaucoup de gain grâce au remaniement/optimisation. Que feriez-vous pour l'accélérer dans ce cas, à moins de le réécrire en C?

s'il vous Plaît rester loin de l'optimisation générale des techniques, à moins qu'ils sont Perl spécifique .

j'ai demandé ceci au sujet de Python plus tôt, et j'ai pensé qu'il pourrait être bon de le faire pour d'autres langues (je suis particulièrement curieux s'il y a des corollaires à psycho et pyrex pour Perl).

28
demandé sur Community 2008-10-07 07:23:24

12 réponses

s'il vous Plaît rappelez-vous les règles de l'Optimisation du Club:

  1. la première règle du club D'optimisation est, vous n'avez pas Optimiser.
  2. la deuxième règle du club D'optimisation est de ne pas optimiser sans mesurer.
  3. si votre application tourne plus vite que le protocole de transport sous-jacent, l'optimisation est terminée.
  4. un facteur à la fois.
  5. Pas de marketroids, pas de marketroid annexe.
  6. les tests se poursuivront aussi longtemps qu'il le faudra.
  7. si c'est votre première nuit au Club D'optimisation, vous devez écrire un cas de test.

ainsi, en supposant que vous avez effectivement le code de travail, lancez votre programme sous Devel::NYTProf .

Trouver les goulots d'étranglement. Puis revenez ici pour nous dire ce qu'ils sont.

Si vous ne pas avoir le code de travail, le faire fonctionner en premier. La plus grande optimisation que vous ferez jamais passe du non-travail au travail.

153
répondu Andy Lester 2014-04-03 13:03:47

Andy a déjà mentionné Devel:: NYTProf . C'est génial. Vraiment, vraiment génial. Utiliser.

si pour une raison quelconque vous ne pouvez pas utiliser Devel::NYTProf , alors vous pouvez vous rabattre sur le bon vieux Devel::dprof , qui est venu standard avec Perl depuis longtemps maintenant. Si vous avez vrai fonctions (dans le sens mathématique) qui prennent beaucoup de temps à calculer( par exemple, Fibonacci nombres), alors vous pouvez trouver Memoize fournit une certaine amélioration de la vitesse.

beaucoup de mauvaises performances proviennent de structures de données et d'algorithmes inappropriés. Un bon cours en informatique peut vous aider grandement ici. Si vous avez deux façons de faire les choses, et que vous souhaitez comparer leurs performances, le module Benchmark peut également s'avérer utile.

Le suivant Perl "Conseils de 151930920" peut également s'avérer utile ici:

avertissement: j'ai écrit certaines des ressources ci-dessus, donc je peux être biaisé vers eux.

34
répondu pjf 2014-04-03 13:06:11

il y a beaucoup de choses que vous pourriez améliorer, donc vous devez d'abord comprendre ce qui est lent. D'autres ont déjà répondu à cette question. J'en parle un peu dans Mastering Perl aussi.

une liste incomplète de choses à penser pendant que vous écrivez un nouveau code:

  • Profil avec quelque chose comme Devel::NYTProf pour voir où vous passez la plupart de votre temps dans le code. Parfois, c'est surprenant et facile à réparer. Mastering Perl a beaucoup de conseils à ce sujet.

  • Perl doit compiler la source à chaque fois et la compilation peut être lente. Il doit trouver tous les fichiers et ainsi de suite. Voir, par exemple, " a Timely Start " , par Jean-Louis Leroy, où il accélère tout simplement en optimisant l'emplacement des modules dans @INC . Si vos coûts de démarrage sont cher et inévitable, vous pourriez également regarder perls persistants, comme pperl, mod_perl, et ainsi de suite.

  • Regardez certains des modules que vous utilisez. Ils ont de longues chaînes de dépendances juste pour faire des choses simples? Bien sûr, nous n'aimons pas réinventer, mais si la roue que vous voulez mettre sur votre voiture est également livré avec trois bateaux, cinq chèvres, et un cheeseburger, peut-être que vous voulez construire votre propre roue (ou trouver un autre).

  • les appels de méthodes peuvent être coûteux. Dans la suite de tests Perl::Critic, par exemple, ses appels à isa ralentissent les choses. Ce n'est pas quelque chose que vous pouvez vraiment éviter dans tous les cas, mais c'est quelque chose à garder à l'esprit. Quelqu'un a eu une grande citation qui est allé quelque chose comme "personne ne se soucie d'abandonner un facteur de 2; c'est quand vous avez dix personnes qui le font que c'est mauvais.":) Perl v5.22 présente certaines améliorations de rendement à cet égard.

  • si vous appelez les mêmes méthodes coûteuses encore et encore mais obtenir les mêmes réponses, quelque chose comme Memoize pourrait être pour vous. C'est une approximation pour l'appel de méthode. Si c'est vraiment une fonction (c'est-à-dire qu'une même entrée donne la même sortie sans effets secondaires), vous n'avez pas vraiment besoin de l'appeler à plusieurs reprises.

  • Modules tels que Apache:: DBI peut réutiliser des poignées de base de données pour vous d'éviter les ouverture coûteuse des connexions de base de données. C'est du code très simple, donc regarder à l'intérieur peut vous montrer comment faire même si vous n'utilisez pas Apache.

  • Perl ne fait pas l'optimisation de la récursion de la queue pour vous, alors ne venez pas de Lisp pensant que vous allez faire ces algorithmes super rapides de récursion. Vous pouvez les transformer en solutions itératives facilement (et nous en parlons dans Perl Intermédiaire .

  • regardez vos regexes. Beaucoup de quantificateurs ouverts (par exemple .* ) peuvent conduire à beaucoup de traçage. Consultez le Mastering Regular Expressions de Jeffrey Freidl pour tous les détails sanglants (et dans plusieurs langues). Aussi vérifier son site web regex .

  • savoir comment votre perl est compilé. Avez-vous vraiment besoin de filetage et DDEBUGGING ? Ceux lent vous un peu à la baisse. Consultez l'utilitaire perlbench pour comparer différents binaires perl.

  • Comparez votre application à différents niveaux. Certaines versions plus récentes ont des vitesses, mais aussi certaines versions plus anciennes peuvent être plus rapides pour des ensembles limités d'opérations. Je n'ai pas de conseil particulier puisque je ne sais pas ce que vous faites.

  • répartir le travail. Pouvez-vous faire quelque travail asynchrone dans d'autres processus ou sur des ordinateurs distants? Laissez votre programme travailler sur d'autres choses comme quelqu'un d'autre comprend quelques sous-problèmes. Perl dispose de plusieurs modules asynchrones et de transfert de charge. Attention, cependant, que l'échafaudage pour bien faire ce genre de choses pourrait perdre tout avantage à le faire.

29
répondu brian d foy 2015-05-08 16:34:54

sans avoir à réécrire de gros morceaux, vous pouvez utiliser Inline::C pour convertir n'importe quel sous-programme lent en C. ou directement utiliser XS. Il est également possible de convertir progressivement les sous-marins avec XS. PPP/PPI::XS le fait, par exemple.

mais passer à une autre langue est toujours le dernier recours. Peut-être que tu devrais demander à un programmeur Perl expert de regarder ton code? Plus probablement que non, (s)il a repéré quelque particularité qui est ça nuit sérieusement à ta performance. À part ça, profile ton code. Rappelez-vous, il n'y a pas de solution miracle.

en ce qui concerne psyco et pyrex: Non, il n'y a pas d'équivalent pour Perl.

14
répondu tsee 2014-04-03 13:09:04

cela ne concerne que la moitié de votre question - mais dans l'intérêt de la documentation, je vais le poster ici.

Un récent CentOS/Perl correction l'augmentation de la vitesse de notre application plus de deux fois. C'est un must pour quiconque exécute CentOS Perl et utilise les fonctions bless/overload.

9
répondu leek 2008-10-07 07:15:06

profil de votre application-en utilisant par exemple, le profileur mentionné ci-dessus. Vous verrez alors où va le temps

si le temps est passé à faire des choses autres que L'utilisation du CPU, vous devez réduire ces premières - CPU est facile à mettre à l'échelle, d'autres choses ne sont pas.

quelques opérations sont particulièrement lentes, j'ai trouvé:

  • keys() sur une grande hachage est très mauvais
  • utilisation de Data::Dumper pour le débogage. Utiliser cette fonction sur une grande structure est très lent. Éviter si vous le pouvez. Nous avons vu le code qui fait:

    use Data::Dumper; 
    $debugstr = Dumper(\%bighash); 
    if ($debugflag_mostlyoff) { log($debugstr); } 
    
  • la plupart des modules ont des alternatives avec des caractéristiques de performance différentes - certains sucent littéralement incroyablement mal.

  • certaines expressions régulières peuvent être très lentes (beaucoup de .* etc) et peuvent être remplacés par des équivalents plus rapides. Régulier les expressions sont assez faciles à unit test et performance test (il suffit d'écrire un programme qui l'exécute dans une boucle contre un jeu de données simulé). Les meilleures expressions régulières commencent par quelque chose qui peut être testé très rapidement, comme une chaîne littérale. Parfois, il est préférable de ne pas chercher la chose que vous cherchez d'abord, et de faire un "coup d'œil derrière" pour vérifier si c'est vraiment la chose que vous cherchez. Optimiser regexps est vraiment un peu d'un art noir à laquelle je ne suis pas très bon.

N'envisagez pas de réécrire quelque chose en C, sauf en dernier recours. Appeler C de Perl (ou vice versa) a un frais généraux relativement important. Si vous pouvez obtenir une implémentation rapide de Perl, c'est mieux.

si vous réécrivez quelque chose en C, essayez de le faire d'une manière qui minimise les frais généraux d'appel et les appels à l'exécution perl (les fonctions SV* par exemple copient principalement des chaînes autour). Une façon d'y parvenir est de faire une fonction C ce qui fait plus et l'appelle moins de fois. Copier des chaînes en mémoire n'est pas cool.

d'un autre côté, réécrire quelque chose en C comporte un grand risque parce que vous pouvez introduire de nouveaux modes de défaillance, par exemple des fuites de mémoire, des accidents, des problèmes de sécurité.

9
répondu MarkR 2013-01-11 15:13:03

un essai qui vaut la peine d'être lu sur le sujet est le discours de Nicholas Clark quand perl n'est pas assez rapide (PDF). Certains points sont légèrement datés, comme la référence à Devel::DProf, mais gardez à l'esprit qu'il a été écrit en 2002.

néanmoins, une grande partie du matériel couvert demeure pertinente.

9
répondu dland 2018-01-08 09:39:35
La méthode

et les appels de sous-programmes ne sont pas gratuits en Perl. Ils sont relativement chers. Donc, si votre profilage s'avère que vous passez une partie relativement importante du temps d'exécution dans des méthodes de petits accesseurs, cela pourrait être une micro-optimisation qui mérite d'être examinée.

cependant, ce que vous devriez et non est de remplacer des accesseurs tels que get_color () ici:

package Car;
# sub new {...}

sub get_color {
   my $self = shift;
   return $self->{color};
}

package main;
#...
my $color = $car->get_color();

avec accès direct cassant l'encapsulation:

my $color = $car->{color};

on pourrait penser que cela va de soi, mais on voit aussi que cela se fait partout. Voici ce que vous pouvez faire, en utilisant la classe :: Xsaccesseur

package Car;
# sub new {...}
use Class::XSAccessor
  getters => {
    get_color => 'color',
  },
  setters => {
    set_color => 'color',
  };

cela crée de nouvelles méthodes get - et set_color() qui sont implémentées dans XS et donc environ deux fois plus rapides que votre version roulée à la main. Les mutants (i.e. "$car - > color ('red')") sont également disponibles, tout comme les méthodes enchaînées.

Selon votre application, cela peut vous donner un très petit coup de pouce (mais essentiellement gratuit). N'attendez pas plus de 1-2% à moins que vous ne fassiez quelque chose de particulier.

7
répondu tsee 2014-04-03 13:10:24

la meilleure façon de rendre votre programme plus rapide est de le rendre moins efficace. Choisir le bon algorithme pour le travail. J'ai vu beaucoup d'applications lentes parce qu'ils ont choisi un algorithme stupide dans une zone du code qui est appelé des millions de fois. Lorsque vous faites un million d' * un million d'opérations au lieu de seulement un million d'opérations, votre programme va exécuter un million de fois plus lent. Littéralement.

par exemple, voici un code que j'ai vu insère un élément dans une liste triée:

while(my $new_item = <>){
    push @list, $new_item;
    @list = sort @list;
    ... use sorted list
}

sort est O (N log n). Une insertion dans une liste triée est O(log n).

Correction de l'algorithme.

6
répondu jrockway 2009-01-12 12:39:11

la méthode la plus rentable pourrait être d'envisager un matériel plus rapide (=> architecture matérielle appropriée). Je ne parle pas de processeurs plus rapides, mais plutôt de disques plus rapides, de réseaux plus rapides .. plus vite n'importe quoi, vraiment, qui accélère I/O.

j'en ai fait l'expérience il y a de nombreuses années, lorsque nous avons déplacé une application basée sur L'analyse XML (technologie de pointe) de a (rapide et fiable!) Windows Server à une plate-forme SUN dédiée, bien que quelque peu obsolète, avec plus vite j'/S tout autour.

comme toujours, considérer

  • développeur de performance (combien de temps faut-il pour le code, comment complexe est le problème, est le résultat maintenable),
  • la performance du Matériel,
  • les performances du Logiciel

et d'améliorer où le plus (coût!) efficace pour le problème en question...

2
répondu Peter Mortensen 2010-03-26 20:17:22

si votre code a besoin d'être accéléré, il y a des chances que votre suite de test le fasse aussi. Cet exposé aborde les points clés:

Turbo Suites De Test

1
répondu EvdB 2008-10-10 12:46:16

larguer Perl et utiliser Golang. J'ai changé mon programme pour utiliser Go et il spead le runtime up de 34 fois. C'est le Perl temps d'Exécution.

real 0m16.724

C'est L'heure.

real 0m0.425s

-1
répondu Gogol 2017-08-13 06:13:11