2009-05-07 3 views
5

Quanto più lentamente posso ragionevolmente aspettarmi che sia perform: che inviare un messaggio letterale, in media? Dovrei evitare di inviare perform: in un ciclo, simile all'ammonimento dato ai programmatori Perl/Python per evitare di chiamare eval("...") (Compiler evaluate: in Smalltalk) in un ciclo?Prestazioni generali delle prestazioni: in Smalltalk (in particolare Squeak)

Sono interessato principalmente a Squeak, ma sono interessato anche ad altre Smalltalks. Inoltre, l'overhead è maggiore con le varianti perform:with:? Grazie

risposta

8

#perform: non è come eval(). Il problema con eval() (per quanto riguarda le prestazioni, comunque) è che deve compilare il codice che si sta inviando al runtime, operazione molto lenta. Smalltalk's #perform:, d'altra parte, è equivalente a Ruby send() o Objective-C performSelector: (in realtà, entrambi questi linguaggi sono stati fortemente ispirati da Smalltalk). Lingue come queste già cercano metodi basati sul loro nome - #perform: ti permettono solo di specificare il nome in fase di esecuzione piuttosto che in fase di scrittura. Non deve analizzare alcuna sintassi o compilare qualcosa come eval().

Sarà un po 'più lento (il costo di una chiamata di metodo in più almeno), ma non è come eval(). Inoltre, le varianti con più argomenti non dovrebbero mostrare alcuna differenza di velocità rispetto al semplice perform:whatever. Non posso parlare con quella esperienza su Squeak in particolare, ma è così che generalmente funziona.

2

Ecco alcuni numeri da mia macchina (è Smalltalk/X, ma credo che i numeri sono paragonabili - almeno i rapporti dovrebbero essere):

I cosiddetti metodi di "pippo" e "foo:" sono un noops (cioè consistono in un sé):

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 

Notare la grande differenza tra "eseguire:" e "valutare:"; valutare sta chiamando il compilatore per analizzare la stringa, generare un metodo throw-away (bytecode), eseguirlo (viene eseguito sulla prima chiamata) e infine scartato. Il compilatore è in realtà scritto per essere usato principalmente per l'IDE e per fileIn codice da flussi esterni; ha il codice per la segnalazione degli errori, i messaggi di avviso, ecc. In generale, l'eval non è ciò che si vuole quando le prestazioni sono critiche.

Intervalli da un Dell Vostro; la tua milizia può variare, ma i rapporti no. Ho cercato di ottenere i tempi di esecuzione netti, misurando il tempo del ciclo vuoto e sottraendo; Inoltre, ho eseguito i test 10 volte e ho preso i migliori tempi, per eliminare OS/rete/disco/email o qualsiasi disturbo. Tuttavia, non mi importava davvero di una macchina senza carico. Il codice misura è stata (sostituito secondo timesRepeat-arg con la roba sopra):

callFoo2 
    |t1 t2| 

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

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

    Transcript showCR:t2-t1 

EDIT: PS: Ho dimenticato di dire: questi sono i tempi dall'interno IDE (esecuzione cioè bytecode-jitted) . Il codice compilato staticamente (usando lo stc-compiler) sarà generalmente un po 'più veloce (20-30%) su questi micro benchmark di basso livello, grazie ad un migliore algoritmo di allocazione dei registri.

EDIT: Ho cercato di riprodurre questi numeri l'altro giorno, ma ho ottenuto risultati completamente diversi (8ns per la chiamata semplice, ma 9ns per l'esecuzione). Quindi, sii molto attento con questi micro-tempi, poiché vengono eseguiti completamente fuori dalla cache di primo livello (e i messaggi vuoti omettono perfino l'impostazione del contesto o vengono sottolineati) - di solito non sono molto rappresentativi delle prestazioni complessive.