2009-05-07 15 views
5

Combien de temps est-ce que je peux raisonnablement attendre que perform: soit plus qu'un envoi de message littéral, en moyenne? Dois-je éviter d'envoyer perform: dans une boucle, semblable à l'avertissement donné aux programmeurs Perl/Python pour éviter d'appeler eval("...") (Compiler evaluate: dans Smalltalk) dans une boucle?Performance overhead de performance: dans Smalltalk (spécifiquement Squeak)

Je m'intéresse principalement à Squeak, mais je m'intéresse aussi aux autres Smalltalks. En outre, les frais généraux sont-ils plus élevés avec les variantes perform:with:? Merci

Répondre

8

#perform: n'est pas comme eval(). Le problème avec eval() (performance-sage, de toute façon) est qu'il doit compiler le code que vous l'envoyez à l'exécution, qui est une opération très lente. D'autre part, #perform: de Smalltalk est équivalent à send() de Ruby ou à performSelector: d'Objective-C (en fait, ces deux langages ont été fortement inspirés par Smalltalk). Des langages comme ceux-ci recherchent déjà des méthodes basées sur leur nom - #perform: vous permet juste de spécifier le nom à l'exécution plutôt que l'heure d'écriture. Il n'a pas besoin d'analyser une syntaxe ou de compiler quelque chose comme eval().

Il sera un peu plus lent (le coût d'un appel de méthode supplémentaire au moins), mais ce n'est pas comme eval(). En outre, les variantes avec plus d'arguments ne doivent pas montrer de différence de vitesse par rapport à perform:whatever. Je ne peux pas parler avec autant d'expérience sur Squeak, mais c'est comme ça que ça fonctionne généralement.

2

Voici quelques chiffres de ma machine (il est Smalltalk/X, mais je suppose que les chiffres sont comparables - au moins les rapports devraient être):

Les méthodes dites « foo » et « foo: » sont un noops (ie consistent en un^auto):

self foo        ... 3.2 ns 
self perform:#foo      ... 3.3 ns 
[self foo] value      ... 12.5 ns (2 sends and 2 contexts) 
[ ] value        ... 3.1 ns (empty block) 
Compiler valuate:('TestClass foo')  ... 1.15 ms 

self foo:123       ... 3.3 ns 
self perform:#foo: with:123   ... 3.6 ns 
[self foo:123] value     ... 15 ns (2 sends and 2 contexts) 
[self foo:arg] value:123    ... 23 ns (2 sends and 2 contexts) 
Compiler valuate:('TestClass foo:123') ... 1.16 ms 

Notez la grande différence entre "effectuer:" et "évaluer"; evaluate appelle le compilateur pour analyser la chaîne, générer une méthode throw-away (bytecode), l'exécuter (il est jeté lors du premier appel) et finalement rejeté. Le compilateur est en fait écrit pour être utilisé principalement pour l'IDE et pour le code fileIn de flux externes; Il a un code pour les rapports d'erreurs, les messages d'avertissement, etc. En général, eval n'est pas ce que vous voulez quand les performances sont critiques.

Délais d'un Dell Vostro; votre kilométrage peut varier, mais pas les ratios. J'ai essayé d'obtenir les temps d'exécution du réseau, en mesurant le temps de boucle vide et en soustrayant; aussi, j'ai couru les tests 10 fois et pris les meilleurs temps, pour éliminer OS/réseau/disque/e-mail ou autres perturbations. Cependant, je ne me souciais pas vraiment d'une machine sans charge. Le code de mesure a été (a remplacé le deuxième timesRepeat-arg avec les choses ci-dessus):

callFoo2 
    |t1 t2| 

    t1 := 
     TimeDuration toRun:[ 
      100000000 timesRepeat:[] 
     ]. 

    t2 := 
     TimeDuration toRun:[ 
      100000000 timesRepeat:[self foo:123] 
     ]. 

    Transcript showCR:t2-t1 

EDIT: PS: J'ai oublié de mentionner: ce sont les temps depuis l'EDI (c.-à-bytecode-jitted exécution) . Le code compilé statiquement (en utilisant le compilateur stc) sera généralement un peu plus rapide (20-30%) sur ces micro-tests de bas niveau, grâce à un meilleur algorithme d'allocation de registres.

EDIT: J'ai essayé de reproduire ces chiffres l'autre jour, mais j'ai obtenu des résultats complètement différents (8ns pour l'appel simple, mais 9ns pour l'exécution). Soyez donc très prudent avec ces micro-timings, car ils fonctionnent complètement hors du cache de premier niveau (et les messages vides omettent même la configuration de contexte, ou sont insérés) - ils ne sont généralement pas très représentatifs de la performance globale.