Dans l'exemple Module ci-dessous, les getters et les setters sont générés en ajoutant des sous-programmes anonymes à la table des symboles. Une fois que les méthodes ont été créées de cette manière, le code résultant sera-t-il fonctionnellement équivalent fonctionnellement (en termes de comportement, de vitesse, etc.) à un module avec des getters et des ensembles écrites manuellement, ou cette approche a-t-elle une sorte de responsabilité inhérente? (J'ai fait une analyse comparative de la vitesse de base et n'a pas détecté de différences jusqu'à présent.)
package Module; use strict; use warnings; BEGIN { my @attr = qw(author title number); no strict 'refs'; for my $a (@attr){ *{__PACKAGE__ . "::get_$a"} = sub { $_[0]->{$a} }; *{__PACKAGE__ . "::set_$a"} = sub { $_[0]->{$a} = $_[1] }; } } sub new { my $class = shift; bless { @_ }, $class; } 1;
7 Réponses :
Il n'y a pas de différence car: est juste un raccourci pour: p> référence de perlmod p> p>
Les deux approches ont le résultat de l'installation d'une référence de sous-programme dans la table des symboles lors de la compilation. Les performances du comportement et de l'exécution seront exactement les mêmes. Il pourrait y avoir une très petite différence (c'est-à-dire négligeable) dans le temps de compilation. P>
Une approche similaire consiste à générer des accesseurs à la demande via Évidemment, les méthodes génératrices les cacheront de toute forme d'analyse statique, y compris des outils tels que CTAGS. P> autoluoad code>, ce qui a un faible impact au moment de l'exécution. À l'aide de l'approche
autoload code> peut également modifier le comportement des choses comme
$ objet-> peut () code>. P>.
Sérieusement. N'utilisez pas d'autoload pour de telles choses. Il ouvre les portes d'inondation à la folie. (Je suis à peu près sûr que vous, MC, savez que :)
AVERTISSEMENT: CODE> B> N'utilisez pas
AutoLoad code> sauf si vous savez exactement b> Qu'est-ce que vous faites.
Le comportement et la performance d'exécution devraient être la même chose (sauf si vous faites quelque chose qui se soucie de savoir si les méthodes sont des fermetures ou non).
Avec un grand nombre d'attributs, il y aura une différence de compilation de temps et de mémoire Utilisez ... à la fois en faveur des getters et des setters générés, pas les écrites manuellement.
Essayez, par exemple, ceci: p> comparé à p>
Il ne devrait y avoir aucune différence dans les performances d'exécution si em> le code résultant est la même dans les deux cas. Ceci n'est généralement pas possible, cependant, à moins que vous utilisiez une chaîne eval code> pour créer vos sous-routines. Par exemple, le code que vous avez fourni:
Rate dynamic_index manual_index dynamic_shift manual_shift eval_shift eval_index
dynamic_index 1820444/s -- -1% -2% -3% -4% -5%
manual_index 1835005/s 1% -- -1% -2% -3% -4%
dynamic_shift 1858131/s 2% 1% -- -1% -2% -3%
manual_shift 1876708/s 3% 2% 1% -- -1% -2%
eval_shift 1894132/s 4% 3% 2% 1% -- -1%
eval_index 1914060/s 5% 4% 3% 2% 1% --
Votre EVAL_INDEX a besoin de $ en $ _ [0] échappé.
Si vous allez générer des accesseurs, vous pouvez également utiliser un générateur rapide. Cf. Search.cpan.org/dist/class-xsaccessor qui sera plus rapide que tout sauf accès à hachage direct.
YSTH: Merci, je pense que la barre oblique inverse a été mangée tout en étant édité localement. Je l'ai corrigé.
Ajoutez ceci au repère " subven_alias {My ($ arg) = @ _; $ arg -> {'$ attr'}} code>"
Brad Gilbert: Je l'ai essayé et c'est le plus lent de loin: eval_alias 1329967 / s
$ Ne serait-il pas allé dans chaque sous-définition comme fermeture? $ A ne devrait pas exister au moment de l'exécution; Ce serait maintenant une constante, ce qui rendrait donc le sous-identique à la forme écrite manuelle.
La seule différence est le temps de démarrage. Pour simples schémas de génération de code, la différence sera difficile à mesurer. Pour des systèmes plus complexes, il peut s'ajouter. P>
Un excellent exemple de ceci en action est Moose . Moose fait toutes sortes de générations de code étonnantes pour vous, mais elle a un impact significatif sur les temps de démarrage. Il suffit d'un problème que les Devs Moose travaillent sur a Schéma de cache Code généré dans les fichiers PMC et chargez-les au lieu de régénérer le code à chaque fois. P>
considère également quelque chose comme classe :: structure . Il utilise la génération de code utilisant String Eval (la dernière fois que j'ai vérifié). Malgré tout, parce que c'est très simple, cela ne provoque pas de ralentissement important au démarrage. P>
L'inconvénient principal d'accesseurs bien générés est qu'ils vaincre des outils qui s'appuient sur une analyse statique. La méthode de votre IDE est l'achèvement automatique par exemple. Si cela fait partie d'un grand projet, je vous recommande de bien jeter un coup d'œil à Moose . C'est la génération des accessoires à droite (et bien plus encore). Il est suffisamment populaire que le soutien soit ajouté aux IDes, de sorte que la question susmentionnée disparaisse en temps voulu. P>
Il existe de nombreux générateurs d'accesseurs sur CPAN, faciles à utiliser et à générer du code modérément efficace. Si la performance est un problème, il vous suffit d'utiliser des méthodes d'accesseur - vous ne pouvez pas obtenir de plus vite que Classe :: Xsaccessor Comme il utilise un code C / X hautement optimisé pour les accesseurs. P>
Rouler votre propre code générateur d'accessor est la pire de toutes les options. Il défait l'analyse statique pour toujours, est probablement plutôt difficile à lire et introduit potentiellement de nouveaux bugs. P>
Mis à part les excellents points que les autres ont mentionné, j'aimerais également ajouter l'inconvénient principal que j'ai trouvé: ils apparaissent tous comme des sous-programmes anonymes dans le profileur. Pour une raison quelconque, devel :: DProf ne sait pas comprendre comment comprendre le nom. p>
Maintenant je voudrais espoir em> que le nouveau devel :: nytprof peut faire un meilleur travail - mais je ne l'ai pas essayé. P>
* {"get_ $ a"} = sous code> ... devrait également fonctionner. (Pas besoin d'avoir
__ paquet __ code> là-bas)