Performance Unterschied: MethodInfo.Invoke <-> Linq.Expressions
-
Jetzt wird es interessant ...
Ich habe erwartet, dass die Mastervorlesung heute etwas langweilig werden würde und habe daher die Unterlagen für diese Tests mitgenommen. Als ich nun die Tests auf dem Laptop hier ausgeführt habe, kam dieses Ergebnis heraus:Linq.Expression: 183 ms Method.Invoke: 467 ms
Der Unterschied ist bei weitem nicht mehr so extrem.
Gut, der Test oben ist auf einem älteren PC gemacht worden (Core2Duo, E7600?, 3 Ghz) und der Laptop ist sehr neu (i7-3632QM, 2.2 GHz). Aber kann das wirklich so einen Unterschied ausmachen? Ich meine auf der alten Maschine war der Unterschied zwischen dem 12-13-fachem und auf dem neuen Laptop ca. 2.5?
Aber dafür ist seltsamerweise das Linq.Expression Beispiel konstant bis zu ca. 40ms langsamer. Ich probiere schon alle möglichen Einstellungen aus, aber ich kann das nicht nachvollziehen. Muss es dann nochmals am Abend genauer anschauen, bzw. vergleichen, und ein sauberes neues Projekt machen...Grüssli
PS: Habe nachwievor nichts gegen Hinweise oder ähnliches
-
Hast du meins eigentlich gelesen oder gekonnt ignoriert
-
Firefighter schrieb:
Hast du meins eigentlich gelesen oder gekonnt ignoriert
Hab es gelesen, nur was soll ich darauf erwidern? Ich kann mir schlecht vorstellen, dass dies so viel ausmacht. Das würde eher in den Bereich meiner zweiten Messergebnisse fallen.
Und habe nun nochmals alles sauber getestet. Beide Messergebnisse sind "korrekt". Gleiches Projekt, nur unterschiedliche Computer und daraus resultieren diese Differenzen.
Das eine ist mein Laptop, hier kommt die kleine Differenz heraus:
i7-3632QM, 2.2 GHz, Win8 x64, 8 GB DDR3 RAMDas andere ist mein Desktop, hier hat es diese riesige Differenz:
Core2Duo E8400, 3.0 GHz, Win7 x64, 6 GB DDR2 RAMBeiden Orten ist das .Net Framework 4.0 installiert, beiden Orten mit Visual Studio 2010 kompiliert. Kein .Net Framework 4.5 im Einsatz oder sowas.
Irgendeine Vermutung? Ich schaue nur noch völlig verwundert meinen Bildschirm an und habe keinen Schimmer, wieso es zu einer so grossen Differenz kommen kann.
Grüssli
-
Hmm...Mir faellt auch nichts mehr ein. Einzige Idee waere noch mit einem Profiler zu schauen was da so lange dauert.
-
Dravere schrieb:
Ich kann mir schlecht vorstellen, dass dies so viel ausmacht. Das würde eher in den Bereich meiner zweiten Messergebnisse fallen.
Ich kann da jetzt auch nichts dazu sagen. Ich hab aber mal irgendwo in irgendeinem Forum gelesen, dass Graphics.CopyFromScreen angeblich viel langsamer sei, als BitBlt. Und CopyFromScreen macht auch nur BitBlt + Security Checks. Also keine Ahnung, vielleicht kann das u.U. tatsächlich sehr viel ausmachen.
-
Firefighter schrieb:
Hmm...Mir faellt auch nichts mehr ein. Einzige Idee waere noch mit einem Profiler zu schauen was da so lange dauert.
Der sagt mir, der Prozess sei in der
clr.dll
... mehr nichtMechanics schrieb:
Ich kann da jetzt auch nichts dazu sagen. Ich hab aber mal irgendwo in irgendeinem Forum gelesen, dass Graphics.CopyFromScreen angeblich viel langsamer sei, als BitBlt. Und CopyFromScreen macht auch nur BitBlt + Security Checks. Also keine Ahnung, vielleicht kann das u.U. tatsächlich sehr viel ausmachen.
Sagen wir die Sicherheitscheck verbraten die Differenz zum 2.5-Fachen mehr beim Laptop. Könnte ich mir tatsächlich noch vorstellen. Aber die Differenz beim PC ist mir dann nachwievor völlig unerklärlich. Das kann doch nicht sein...
Habt ihr den Code mal bei euch getestet? Was erhaltet ihr so für Werte?
Grüssli
-
Habs grad ausprobiert:
Linq.Expression: 193 ms
Method.Invoke: 4374 msDeiner ist schneller
-
Linq.Expression: 75 ms
Method.Invoke: 432 ms99,09% Main
- 67,95 % TestWithMethodInvoke
-- 57,97 % Invoke
--- 55,41 % Invoke
---- 25,58 % UnsafeInvokeInternal
----- 10,14 % TestMethod
---- 18,54 % InvokeArgumentCheck
---- 05,29 % PerformSecurityCheck
---- 01,00 % get_InvovationFlags- 29,78 % TestWithExpressions
-- 10,39 % TestMethod
-- 07,76 % CompileMethod
-
Ich benutze Invoke immer, um vom Workerthread auf den UI-Thread zu kommen. Ist der Threadwechsel das teure?
-
volkard schrieb:
Ich benutze Invoke immer, um vom Workerthread auf den UI-Thread zu kommen. Ist der Threadwechsel das teure?
*Lach* - vielleicht solltest du die Frage nochmal reflektieren
Es geht um Zeile 72 und Zeile 82 von Dravere Code - Reflection in .NET
-
Ich komme auf folgende Werte:
Linq.Expression: 66 ms Method.Invoke: 1021 ms
P.S. Eure Kisten sind ja lahm :p
P.S. 2: Man kann die Laufzeiten mit Reflection auf ca. 1/2 der LINQ-Expression Lösung drücken, wenn man von Method.Invoke weggeht und ein Delegate erstellt, welches mit der MethodInfo werkelt
-
GPC schrieb:
P.S. Eure Kisten sind ja lahm :p
Wird sind halt arme Leute und schwimmen nicht im Geld
GPC schrieb:
P.S. 2: Man kann die Laufzeiten mit Reflection auf ca. 1/2 der LINQ-Expression Lösung drücken, wenn man von Method.Invoke weggeht und ein Delegate erstellt, welches mit der MethodInfo werkelt
Kannst du das ein wenig näher erläutern? Mit dem
Linq.Expression
wird ja bereits ein Delegate erzeugt.Grüssli
-
Dravere schrieb:
GPC schrieb:
P.S. 2: Man kann die Laufzeiten mit Reflection auf ca. 1/2 der LINQ-Expression Lösung drücken, wenn man von Method.Invoke weggeht und ein Delegate erstellt, welches mit der MethodInfo werkelt
Kannst du das ein wenig näher erläutern? Mit dem
Linq.Expression
wird ja bereits ein Delegate erzeugt.Na logisch
Im Prinzip ist es ganz einfach: Anstatt Method.Invoke zu benutzen, erzeugt man einfach mit der MethodInfo ein Delegate und führt darüber dann den Code aus:
private static long TestWithMethodInvoke(int times) { var obj = new Program(); var method = obj.GetType().GetMethod("TestMethod"); object first = 0m; object second = 1m; //Awesomeness happens here Func<decimal, decimal, decimal> m = (Func<decimal, decimal, decimal>)Delegate.CreateDelegate(typeof(Func<decimal, decimal, decimal>), obj, method); var stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i < times; ++i) { first = m((decimal)first, (decimal)second); } stopwatch.Stop(); return stopwatch.ElapsedMilliseconds; }
Das gibt dann im Debug-Mode ca. solche Zeiten:
Linq.Expression: 65 ms Method.Invoke: 30 ms
-
Warning sematische Optimierung gefunden!
Linq.Expression: 57 ms
Method.Invoke: 36 msgrml nur 2ms schneller als gpc mit schlechteren Rechner
-
@GPC,
Dann kannst du ja auch gleich einDelegate
durchreichen.In meinem Beispiel bin ich sehr generisch und arbeite mit
object
. Ich verwandle jedeMethodInfo
in einFunc<object[], object>
. Das Array, welches übergeben wird, enthält an der Indexposition 0 das Objekt der Methode und im Rest des Arrays befinden sich die Parameter. Damit kannst du eine Methode aufrufen, nur in dem du den Namen von dieser Kennst, das Objekt dazu bekommst und die Parameter als Liste vonobject
. Kann man z.B. sehr gut in einer Skriptsprache verwenden, wo deine Methode nicht funktionieren würdeGrüssli
-
Da hast du natürlich Recht, man büßt ein gutes Stück Verallgemeinerung ein ;/ Ich hatte das damals gebraucht, um einen festen Satz an Methoden per Reflection auf verschiedene COM-Komponenten aufzurufen. Insofern war die Methodensignatur bei mir statisch
Mich interessiert aber auch, wieso Methode.Invoke sooo viel langsamer ist.. mal nach der Mittagspause forschen