11
votes

Une alternative plus rapide à EVAL?

Je traite avec une application Web qui utilise un système de modèles cultivé maison qui permet à Perl Code est intégré au HTML. Ces affirmations sont exécutées par l'analyseur de modèle au moment de l'exécution à l'aide de EVAL EXPR .

Ceci est très flexible, mais ces déclarations sont dispersées partout et obtiennent un lot . EVAL EXPR (par opposition au bloc eval Block ) nécessite Perl d'allumer l'interprète à chaque fois, et mon profilage révèle qu'ils sont une source de ralentissement raisonnablement significative.

Beaucoup de déclarations Perl intégrées sont très simples. Par exemple, un modèle peut avoir une ligne comme celle-ci: xxx

ou: xxx

c'est-à-dire c'est, ils sont juste appeler des méthodes d'objet. Il y a aussi des complexes compliqués aussi.

J'espère optimiser cela, et jusqu'à présent, deux idées, toutes deux terribles. Le premier consiste à réécrire tous les modèles à remplacer des appels simples avec des jetons tels que Utilisateur: nom et utilisateur: GenerateTicketNumber , lequel l'analyseur pourrait ensuite numériser et appeler la méthode d'objet appropriée. Mais au lieu de traiter avec des modèles qui mélangent HTML et Perl, je disposerais de modèles qui mélangent HTML, Perl et Jetkens.

La deuxième idée est d'essayer d'analyser le Perl intégré, de déterminer quelle est la déclaration Veut faire et, si c'est assez simple, appelez la méthode d'objet appropriée via une référence symbolique. Ceci est évidemment fou.

Y a-t-il une solution logique que je vis?


1 commentaires

+1 pour "Ceci est évidemment fou."


4 Réponses :


9
votes

Essayez de prendre une approche similaire à celle que mod_perl utilise pour compiler les CGIS:

  1. Convertissez le modèle en code PERL. Par exemple, votre premier exemple peut convertir quelque chose comme: XXX

  2. enveloppez un SUB { ... } autour de ce code, ainsi que du code pour déballer les arguments (par exemple, pour des éléments tels que $ utilisateur dans l'échantillon).

  3. eval ce code. Notez qu'il renvoie un codèref.

  4. appelez-le à plusieurs reprises. :)


2 commentaires

Une approche connexe consisterait à écrire le code généré dans un fichier .pm , puis chargez ce module. De cette façon, le modèle n'aurait besoin que d'être réparé quand il change. De quelle manière dépend mieux des détails de la mise en œuvre de l'application.


Wow, c'est brillant! Cela me permet de résoudre le problème sans avoir à réécrire un gazillion de modèles. Je vais essayer, merci!



2
votes

Vous voudrez peut-être regarder les courants de Texte :: Microtemplate . De manière réaliste, vous voudrez peut-être utiliser em> Text :: Microtemplate, car il convient probablement à vos besoins. Il construit un sous-programme qui concaténe des cordes au besoin, un peu comme le Duskwuff suggéré. Voici le résultat de build_mt ('Bonjour, = € _ [0]?>') Code> Dans re.pl code>:

$CODE1 = sub {
       package Devel::REPL::Plugin::Packages::DefaultScratchpad;
       use warnings;
       use strict 'refs';
       local $SIG{'__WARN__'} = sub {
         print STDERR $_mt->_error(shift(), 4, $_from);
       }
       ;
       Text::MicroTemplate::encoded_string(sub {
         my $_mt = '';
         local $_MTREF = \$_mt;
         my $_from = '';
         $_mt .= 'hello, ';
         $_from = $_[0];
         $_mt .= ref $_from eq 'Text::MicroTemplate::EncodedString' ? $$_from : do {
           $_from =~ s/([&><"'])/$Text::MicroTemplate::_escape_table{$1};/eg;
           $_from
         };
         return $_mt;
       }
       ->(@_));
     };


1 commentaires

Merci pour l'aide! J'espère échapper à cela sans avoir à remplacer le système de modèles actuel, car ce serait un travail assez énorme. Mais si cela devient trop de problèmes, je vais regarder microtemplate.



3
votes

Vous pouvez regarder Mojolicious . Il a un Moteur de modèles qui permettent une syntaxe proche de ce que vous utilisez. Vous pouvez éventuellement basculer pour l'utiliser ou regarder sa source (Cliquez sur la source à gauche du lien précédent) pour voir si vous pouvez dessiner des idées.

FYI La syntaxe du moteur de modèles mojolcious permet aux formes suivantes entre les formes suivantes avec HTML de manière appropriée P >

<% Perl code %>
<%= Perl expression, replaced with result %>
<%== Perl expression, replaced with XML escaped result %>
<%# Comment, useful for debugging %>
<%% Replaced with "<%", useful for generating templates %>
% Perl code line, treated as "<% line =%>"
%= Perl expression line, treated as "<%= line %>"
%== Perl expression line, treated as "<%== line %>"
%# Comment line, treated as "<%# line =%>"
%% Replaced with "%", useful for generating templates


3 commentaires

Merci! Comme je l'ai posté à Josh, j'espère éviter de devoir remplacer tout le système de modèles, juste parce que c'est un logiciel de 10 ans et ceux qui sont difficiles à modifier. Mais j'ai entendu de bonnes choses à propos de Mojolicious.


Je comprends parfaitement! Toujours peut-être que son code pourrait vous aider avec quelques idées.


@Joelberger partout ailleurs cette question obtiendrait une réponse "idiot utilise une cpan". +1 pour être génial mon ami.



0
votes

Vous ne devez pas utiliser 'eval' pour appeler des méthodes dans votre modèle. Désolé de sonner dure mais le point d'une vue séparée consiste à supprimer le code de traitement de la couche de vue. Les systèmes de modèle décrits ci-dessus avec Toolkit de modèle vous permettent de passer dans un objet / hachage afin que vous puissiez y accéder.

Pourquoi ne pas passer $ utilisateur en tant que hashref comme: p> xxx pré>

Ceci vous permettra d'accéder à "Nom" avec: P>

$user->{'name'};


3 commentaires

J'ai exécuté Nytprof et il semble indiquer que l'évaluation elle-même est une source importante de ralentissement. Cela ne prend que 5 à 10% du temps de serveur total, mais c'est aussi le plus grand point unique. Ce n'est pas vraiment viable de remplacer les appels $ User-> Query ($ de valeur) avec $ utilisateur -> {$ valeur} Comme le et la requête subest souvent vraiment quelque chose au-delà de la simple recherche de la valeur. En outre, c'est juste un appel parmi beaucoup.


Parsim, pourquoi appelez-vous des sous-routines à travailler sur la couche de vue? Tout ce travail ne devrait-il pas être pris en charge avant de sortir le résultat? Peut-être que vous devez envisager de construire un type d'API différent? Si vous appelez en raison de l'interaction de l'utilisateur, il est probablement temps de passer des appels côté serveur via Ajax.


La réponse est l'application Web n'a pas d'architecture MVC. (Est-ce que j'ai mentionné qu'il a presque 10 ans?) Les modèles conduisent efficacement l'application. Ce serait un travail énorme pour changer cela, alors je suis coincé avec ça.