2009-05-07 5 views
5

Wie viel langsamer kann ich vernünftigerweise erwarten perform: als eine wörtliche Nachricht im Durchschnitt zu senden sein? Sollte ich vermeiden, perform: in einer Schleife zu senden, ähnlich der Ermahnung, die Perl/Python-Programmierern gegeben wird, um zu vermeiden, in einer Schleife eval("...") (Compiler evaluate:) in Smalltalk aufzurufen?Leistung Overhead von perform: in Smalltalk (speziell Squeak)

Ich bin hauptsächlich mit Squeak betroffen, aber auch an anderen Smalltalks interessiert. Ist der Overhead mit den perform:with: Varianten größer? Danke

Antwort

8

#perform: ist nicht wie eval(). Das Problem mit eval() (sowieso Leistung) ist, dass es den Code kompilieren muss, den Sie zur Laufzeit senden, was ein sehr langsamer Vorgang ist. Smalltalk's #perform:, auf der anderen Seite, ist Rubys send() oder Objective-C performSelector: (in der Tat waren diese beiden Sprachen stark von Smalltalk inspiriert). Sprachen wie diese suchen bereits nach ihrem Namen - #perform: können Sie nur den Namen zur Laufzeit statt Schreibzeit angeben. Es muss keine Syntax parsen oder irgendetwas wie eval() kompilieren.

Es wird ein wenig langsamer (die Kosten für eine zusätzliche Methode mindestens), aber es ist nicht wie eval(). Auch sollten die Varianten mit mehr Argumenten keinen Geschwindigkeitsunterschied gegenüber perform:whatever zeigen. Ich kann nicht mit so viel Erfahrung über Squeak sprechen, aber so funktioniert es im Allgemeinen.

2

Hier einige Zahlen aus meiner Maschine sind (es ist Smalltalk/X, aber ich denke, die Zahlen sind vergleichbar - zumindest sollten die Verhältnisse sein):

Die genannten Methoden „foo“ und „foo“ sind ein noops (dh aus einer^self):

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 

Hinweis der große Unterschied zwischen "perform:" und "bewerten:"; evaluate ruft den Compiler auf, um die Zeichenfolge zu analysieren, eine Einwegmethode (Bytecode) zu generieren, sie auszuführen (sie wird beim ersten Aufruf aktiviert) und schließlich verworfen. Der Compiler ist eigentlich so geschrieben, dass er hauptsächlich für die IDE und für den fileIn-Code von externen Streams verwendet wird; Es hat Code für Fehlermeldungen, Warnmeldungen usw. Im Allgemeinen ist Eval nicht das, was Sie wollen, wenn die Leistung kritisch ist.

Timings von einem Dell Vostro; Ihr Kilometerstand kann variieren, aber die Verhältnisse nicht. Ich habe versucht, die Netto-Ausführungszeiten zu erhalten, indem ich die leere Schleifenzeit gemessen und subtrahiert habe; auch, führte ich die Tests 10 Mal und nahm die besten Zeiten, um OS/Netzwerk/Festplatte/E-Mail oder was auch immer Störungen zu beseitigen. Eine lastfreie Maschine war mir jedoch nicht wirklich wichtig. Die Maßnahme Code wurde (ersetzt die zweite timesRepeat-Arg- mit dem Zeug oben):

callFoo2 
    |t1 t2| 

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

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

    Transcript showCR:t2-t1 

EDIT: PS: Ich vergaß zu erwähnen: Das sind die Zeiten, in der IDE (dh Bytecode-jitted Ausführung) . Statisch kompilierter Code (unter Verwendung des stc-Compilers) wird im Allgemeinen ein bisschen schneller (20-30%) auf diesen Low-Level-Mikrobenchmarks sein, aufgrund eines besseren Registerzuweisungsalgorithmus.

EDIT: Ich habe versucht, diese Zahlen neulich zu reproduzieren, aber völlig unterschiedliche Ergebnisse (8ns für den einfachen Anruf, aber 9ns für die Leistung). Seien Sie also sehr vorsichtig mit diesen Mikro-Timings, da sie vollständig aus dem Cache der ersten Ebene herauslaufen (und leere Nachrichten sogar das Kontext-Setup auslassen oder inline werden) - sie sind normalerweise nicht sehr repräsentativ für die Gesamtleistung.