Sonntag, Dezember 8, 2019

Leistung überraschung mit „als“ und nullable-Typen

Ich bin nur eine überarbeitung Kapitel 4 in C# in der Tiefe, die sich mit nullable-Typen, und ich bin das hinzufügen einen Abschnitt über die Verwendung des „as“ – operator, welcher Ihnen erlaubt, zu schreiben:

object o = ...;
int? x = o as int?;
if (x.HasValue)
{
    ... //Use x.Value in here
}

Dachte ich, das war wirklich nett, und es könnte verbessern Sie die Leistung über die C# 1 entspricht, mit „“ gefolgt von einer Besetzung – nach allen, diesen Weg, wir brauchen Sie nur zu Fragen für die dynamische Typ-überprüfung einmal, und dann einen einfachen Wert überprüfen.

Dies scheint nicht der Fall zu sein, jedoch. Ich habe einen Probe-test-app unter, die im Grunde die Summen die zahlen in einem object-array, aber das array enthält eine Menge von null-Referenzen und die string-Referenzen als auch als boxed-Ganzzahlen. Der benchmark misst den code müssten Sie zur Verwendung in C# 1, den code über die „wie“ – operator, und einfach nur aus Spaß eine LINQ Lösung. Zu meinem Erstaunen, die C# 1 code 20 mal schneller-in diesem Fall – und auch die LINQ-code (was ich erwartet habe, langsamer zu sein, da die Iteratoren beteiligt) schlägt das „wie“ code.

Ist .NET-Implementierung der isinst für nullable-Typen nur sehr langsam? Ist es das zusätzliche unbox.any, die das problem verursacht? Gibt es eine andere Erklärung dafür? Im moment fühlt es sich wie ich bin zu haben, um eine Warnung gegen die Verwendung dieser Leistung in heiklen Situationen…

Ergebnisse:

Darsteller: 10000000 : 121
Als: 10000000 : 2211
LINQ: 10000000 : 2143

Code:

Warum nicht Blick auf die jitted code? Auch VS-debugger können zeigen.
Ich bin nur neugierig, hast du den test mit CLR 4.0?
Guter Punkt. Tun, an einem gewissen Punkt (obwohl dies nicht in VS im moment 🙂 @divo: ja, und es ist schlimmer, rundum. Aber das ist dann in der beta, also kann es eine Menge von debugging-code drin.
Heute habe ich gelernt, die Sie verwenden können as auf null festlegbaren Typen. Interessant, wie es kann nicht verwendet werden, die auf andere Werttypen. Eigentlich mehr überraschend.
es macht Sinn für es nicht auf den Wert-Typen. Denke, über, as versucht zu werfen, um einen Typ und wenn es dann nicht den Wert null zurück. Sie können nicht von Wert-Typen zu null

InformationsquelleAutor Jon Skeet | 2009-10-17

10 Kommentare

  1. 201

    Klar der Maschinen-code wird der JIT-compiler erzeugen kann, für die der erste Fall ist sehr viel effizienter. Eine Regel, die wirklich hilft, es ist, dass ein Objekt nur ohne Verpackung in eine variable, die denselben Typ wie der boxed Wert. Sie ermöglicht, dass der JIT-compiler erzeugen sehr effizienten code, kein Wert der conversions berücksichtigt werden müssen.

    Den ist operator test ist einfach, einfach prüfen, ob das Objekt nicht null ist und ist von dem erwarteten Typ ist, dauert aber noch ein paar Maschinencode-Anweisungen. Der cast ist auch einfach, der JIT-compiler kennt die Position der Wert-bits im Objekt-und nutzt Sie direkt. Die Vervielfältigung oder Konvertierung stattfindet, werden alle Maschinen-code ist inline-und dauert aber etwa ein Dutzend Anweisungen. Dieser benötigt, um wirklich effizient zurück .NET 1.0 beim Boxen üblich war.

    Casting nach int? braucht viel mehr Arbeit. Der Wert Darstellung der boxed integer ist nicht kompatibel mit der Speicher-layout von Nullable<int>. Eine Konvertierung erforderlich ist, und der code ist tricky wegen möglich, boxed enum-Typen. Der JIT-compiler erzeugt einen Anruf an einen CLR-helper-Funktion mit dem Namen JIT_Unbox_Nullable um den job zu erledigen. Dies ist eine Allgemeine Funktion für einen beliebigen Wert geben, viel code, es zu überprüfen-Typen. Und der Wert wird kopiert. Schwer einzuschätzen sind die Kosten, da dieser code gesperrt ist, innerhalb mscorwks.dll aber Hunderte von Maschinencode-Anweisungen wahrscheinlich ist.

    Linq-OfType () – Erweiterungsmethode verwendet auch die ist Betreiber und die Darsteller. Dies ist jedoch ein cast auf einen generischen Typ. Der JIT-compiler erzeugt ein Aufruf einer Hilfsfunktion, JIT_Unbox() ausführen kann ein cast auf einen beliebigen Wert zu geben. Ich habe keine großartige Erklärung, warum es ist so langsam wie der cast zu Nullable<int> angesichts der Tatsache, dass weniger Arbeit sein sollte, notwendig. Ich vermute, dass ngen.exe könnte Schwierigkeiten verursachen hier.

    Okay, davon bin ich überzeugt. Ich denke, ich bin daran gewöhnt „ist“ als potentiell teurer, da die Möglichkeiten von Wandern bis eine Vererbungshierarchie – aber in dem Fall einen Wert geben, es gibt keine Möglichkeit, eine Hierarchie, so dass es eine einfache bitweise Vergleich. Ich denke immer noch, der JIT-code für die nullable Fall könnte optimiert werden von der JIT-viel stärker als es ist aber.

    InformationsquelleAutor Hans Passant

  2. 26

    Scheint es mir, dass die isinst ist einfach wirklich langsam auf null festlegbaren Typen. In der Methode FindSumWithCast ich geändert

    zu

    welche auch deutlich verlangsamt die Ausführung. Den nur differenc in IL ich sehen kann, ist, dass

    verändert wird, um

    Es ist mehr als das; in der „cast“ Fall der isinst ist, gefolgt von einem test für die Nichtigkeit und dann bedingt ein unbox.any. In der nullable-Fall gibt es ein bedingungslose unbox.any.
    Ja, stellt sich heraus, beide isinst und unbox.any langsamer als auf null festlegbaren Typen.
    Sie können überprüfen, meine Antwort für warum wird der cast benötigt. (Ich weiß, das ist alt, aber ich habe gerade entdeckt, dieses q und dachte, ich sollte meine 2c was ich darüber weiß, von der CLR).

    InformationsquelleAutor Dirk Vollmar

  3. 22

    Dieser begann ursprünglich als ein Kommentar zu Hans Passant ausgezeichnete Antwort, aber es hat zu lange, so möchte ich hinzufügen, dass ein paar bits hier:

    Ersten, die C# as Betreiber Strahlen eine isinst IL-Anweisung (also nicht die is Betreiber). (Eine andere interessante Anweisung ist castclass, emited, wenn Sie einen direkten cast und weiß der compiler, die runtime-überprüfung kann nicht weggelassen werden.)

    Hier ist, was isinst tut (ECMA 335-Partition III, 4.6):

    Format: isinst typeTok

    typeTok ist ein Metadaten-token ( typeref , typedef oder typespec) unter Angabe der gewünschten Klasse.

    Wenn typeTok ist ein null-Wert oder ein generischer parameter Art es ist, interpretiert als „boxed“ typeTok.

    Wenn typeTok ist ein nullable-Typ, Nullable<T> es wird interpretiert als „boxed“ T

    Allem:

    Wenn der tatsächliche Typ (nicht der überprüfer verfolgt-Typ) obj ist verifier-belegbar-zu der Typ typeTok dann isinst gelingt und obj (wie Ergebnis) wird unverändert zurückgegeben, während die überprüfung Spuren seiner Art als typeTok. Im Gegensatz zu Zwang (§1.6) und Umwandlungen (§3.27), isinst nie ändert sich der tatsächliche Typ eines Objekts und bewahrt Objekt-Identität (siehe Partition I).

    So, die performance-killer ist nicht isinst in diesem Fall aber die zusätzlichen unbox.any. Dies war nicht klar, aus Hans‘ Antwort, als er sah das JIT-Anpassung nur code. Im Allgemeinen, der C# – compiler emittiert wird ein unbox.any nach einem isinst T? (aber weglassen, falls Sie isinst T, wenn T ist ein Referenz-Typ).

    Warum tut er das? isinst T? hat nie den Effekt, dass wäre klar gewesen, d.h. Sie erhalten wieder ein T?. Stattdessen werden alle diese Anweisungen sorgen dafür, dass Sie eine "boxed T" werden können, ohne Verpackung zu T?. Um eine tatsächliche T? müssen wir noch unbox unsere "boxed T" zu T?, das ist der Grund, warum der compiler gibt eine unbox.any nach isinst. Wenn Sie darüber nachdenken, das macht Sinn, weil die „Feld-format“ für T? ist nur ein "boxed T" und machen castclass und isinst führen Sie die unbox unvereinbar wäre.

    Sichern Hans‘ Suche nach mit einigen Informationen aus der standard, hier geht es:

    (ECMA 335-Partition III, 4.33): unbox.any

    Wenn es sich um den boxed-form einen Wert geben, der unbox.any Anweisung extrahiert die enthaltenen Wert obj (der Typ O). (Es ist äquivalent zu unbox gefolgt von ldobj.) Bei Anwendung auf ein Referenz-Typ, der unbox.any Anweisung hat die gleiche Wirkung wie castclass typeTok.

    (ECMA 335-Partition III, 4.32): unbox

    Normalerweise unbox einfach berechnet die Adresse den Wert-Typ, der bereits im inneren der Box-Objekt. Dieser Ansatz ist nicht möglich, wenn unboxing nullable value types. Da Nullable<T> Werte konvertiert (boxed Ts während der box-operation, die eine Umsetzung oft muss die Herstellung eines neuen Nullable<T> auf dem heap, und berechnen Sie sich die Adresse den neu zugewiesenen Objekt.

    Ich denke, der Letzte zitierte Satz, der vielleicht ein Tippfehler; sollte nicht „…am heap…“ „auf Ausführung-stack?“ Scheint, wie unboxing zurück in einige neue GC-heap Beispiel swaps das ursprüngliche problem, für eine fast identische neue.

    InformationsquelleAutor Johannes Rudolph

  4. 19

    Interessanterweise habe ich weitergegeben feedback über operator-Unterstützung über dynamic als eine Größenordnung langsamer Nullable<T> (ähnlich dieses frühe testen) – ich vermute, dass bei sehr ähnlichen Gründen.

    Gotta love Nullable<T>. Ein weiterer Spaß ist, dass, obwohl die JIT-spots (und entfernt) null für nicht-nullable structs, es borks es für Nullable<T>:

    Yowser. Das ist ein wirklich schmerzhafter Unterschied. Eek.
    Daher wird von einigen der obskuren code in MiscUtil/Betreiber ;-p
    Wenn keine andere gute gekommen ist, aus all dem, es führte mich zu Warnungen, meine beiden original-code und🙂
    Ich weiß, das ist eine alte Frage, aber könntest du erklären, was du damit meinst „die JIT-spots (und entfernt) null für nicht-nullable structs“? Meinst du es ersetzt null mit einem default-Wert oder etwas, das während der Laufzeit?
    eine generische Methode kann verwendet werden zur Laufzeit mit einer beliebigen Anzahl von Permutationen der generic-Parameter (T etc). Der stack usw-Anforderungen sind abhängig von der args (Betrag der stack Platz für lokale, etc), so erhalten Sie eine JIT-für alle eindeutigen permutation mit einem Wert geben. Aber die Verweise sind alle die gleiche Größe haben, so teilen JIT. Während die pro-Wert-Typ JIT, Sie können überprüfen für ein paar offensichtlichen Szenarien, und bemüht Verbrauchsteuer unreachable code durch Dinge wie unmöglich, null-Werte. Es ist nicht perfekt, beachten. Auch, ich Ignoriere AOT für die oben genannten.

    InformationsquelleAutor Marc Gravell

  5. 12

    Dies ist das Ergebnis FindSumWithAsAndHas oben: alt-text http://www.freeimagehosting.net/uploads/9e3c0bfb75.png

    Dies ist das Ergebnis FindSumWithCast: alt-text http://www.freeimagehosting.net/uploads/ce8a5a3934.png

    Ergebnisse:

    • Mit as es zuerst testen, ob ein Objekt eine Instanz von Int32; unter der Haube ist es mit isinst Int32 (das ist ähnlich wie hand-code geschrieben: if (o is int) ). Und mit as es auch unbedingt unbox das Objekt. Und es ist ein echter performance-killer zu nennen, eine Eigenschaft(es ist immer noch eine Funktion unter der Haube), IL_0027

    • Verwendung von cast, testen Sie zuerst, wenn Objekt ist eine int if (o is int); unter der Haube, diese ist mit isinst Int32. Wenn es eine Instanz von int, dann können Sie sicher unbox der Wert, IL_002D

    Einfach ausgedrückt, ist dies der pseudo-code zu verwenden as Ansatz:

    – Und dies ist der pseudo-code der Verwendung von cast-Ansatz:

    Also der cast ((int)a[i], sowie die syntax sieht aus wie aus einem Guss, aber es ist eigentlich unboxing, cast und unboxing teilen Sie die gleiche syntax, das nächste mal werde ich pedantisch mit der richtigen Terminologie) – Ansatz ist wirklich schneller, Sie brauchte nur zu unbox einen Wert, wenn Sie ein Objekt entschieden eine int. Das gleiche kann nicht gesagt werden, um mit einem as Ansatz.

    InformationsquelleAutor Michael Buen

  6. 9

    Profiling weiter:

    using System;
    using System.Diagnostics;
    class Program
    {
    const int Size = 30000000;
    static void Main(string[] args)
    {
    object[] values = new object[Size];
    for (int i = 0; i < Size - 2; i += 3)
    {
    values[i] = null;
    values[i + 1] = "";
    values[i + 2] = 1;
    }
    FindSumWithIsThenCast(values);
    FindSumWithAsThenHasThenValue(values);
    FindSumWithAsThenHasThenCast(values);
    FindSumWithManualAs(values);
    FindSumWithAsThenManualHasThenValue(values);
    Console.ReadLine();
    }
    static void FindSumWithIsThenCast(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    if (o is int)
    {
    int x = (int)o;
    sum += x;
    }
    }
    sw.Stop();
    Console.WriteLine("Is then Cast: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithAsThenHasThenValue(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    int? x = o as int?;
    if (x.HasValue)
    {
    sum += x.Value;
    }
    }
    sw.Stop();
    Console.WriteLine("As then Has then Value: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithAsThenHasThenCast(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    int? x = o as int?;
    if (x.HasValue)
    {
    sum += (int)o;
    }
    }
    sw.Stop();
    Console.WriteLine("As then Has then Cast: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithManualAs(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    bool hasValue = o is int;
    int x = hasValue ? (int)o : 0;
    if (hasValue)
    {
    sum += x;
    }
    }
    sw.Stop();
    Console.WriteLine("Manual As: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithAsThenManualHasThenValue(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    int? x = o as int?;
    if (o is int)
    {
    sum += x.Value;
    }
    }
    sw.Stop();
    Console.WriteLine("As then Manual Has then Value: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    }

    Ausgabe:

    Is then Cast: 10000000 : 303
    As then Has then Value: 10000000 : 3524
    As then Has then Cast: 10000000 : 3272
    Manual As: 10000000 : 395
    As then Manual Has then Value: 10000000 : 3282

    Was können wir folgern aus diesen zahlen?

    • Zuerst-dann-cast Ansatz ist deutlich schneller als als Ansatz. 303 vs 3524
    • Sekunde .Wert ist geringfügig langsamer als casting. 3524 vs 3272
    • Dritten .HasValue ist geringfügig langsamer als die manuelle(d.h. mit ist). 3524 vs 3282
    • Vierten, tut ein Apfel-zu-Apfel-Vergleich(d.h. beide Zuordnung der simulierten HasValue und Umwandlung von simulierten Wert zusammen passiert) zwischen simuliert und real wie Ansatz, können wir sehen, simuliert ist immer noch deutlich schneller als real wie. 395 vs 3524
    • Schließlich, basierend auf dem ersten und vierten Schluss ziehen, dass es etwas falsch mit als
      die Umsetzung ^_^

    InformationsquelleAutor

  7. 8

    Ich habe keine Zeit, es zu versuchen, aber vielleicht möchten Sie haben:

    foreach (object o in values)
    {
    int? x = o as int?;

    als

    int? x;
    foreach (object o in values)
    {
    x = o as int?;

    Sind Sie ein neues Objekt erstellen jedes mal, die nicht komplett erklären, das problem, kann aber dazu beitragen.

    Ich habe versucht, aber das scheint zu haben wenig Wirkung…
    Nein, ich lief, und es ist geringfügig langsamer.
    Die Deklaration einer Variablen in einen anderen Ort betrifft nur den generierten code erheblich, wenn die variable erfasst wird (an welcher Stelle es wirkt sich auf die tatsächliche Semantik) in meiner Erfahrung. Beachten Sie, dass Sie es nicht schaffen, ein neues Objekt auf dem heap, obwohl es sicherlich erstellen einer neuen Instanz der int? auf dem Stapel mit unbox.any. Ich vermute, das ist das Problem – meine Vermutung ist, dass handgefertigte IL schlagen konnte beide Optionen hier… obwohl es ist auch möglich, dass der JIT optimiert ist, zu erkennen, für die ist/Gussgehäuse und nur einmal überprüfen.
    ist/cast ist ein leichtes Ziel für die Optimierung, es ist so störend gemeinsames idiom.
    Lokale Variablen auf dem Stapel reserviert, wenn der stack-frame für die Methode erstellt, also wo Sie deklarieren Sie die variable in der Methode macht überhaupt keinen Unterschied. (Es sei denn, es ist ein Verschluss natürlich, aber das ist hier nicht der Fall.)

    InformationsquelleAutor James Black

  8. 8

    Habe ich versucht, den genauen Typ überprüfen konstruieren

    typeof(int) == item.GetType(), die verhält sich so schnell wie die item is int version, und gibt immer die Anzahl (Schwerpunkt: selbst wenn Sie schrieb eine Nullable<int> auf die Reihe, du brauchst typeof(int)). Sie müssen auch eine zusätzliche null != item hier überprüfen.

    Jedoch

    typeof(int?) == item.GetType() bleibt schnell (im Gegensatz zu item is int?), aber immer false zurück.

    Den typeof-Konstrukt ist in meinen Augen der Schnellste Weg für genaue Typ-überprüfung, wie es verwendet die RuntimeTypeHandle. Da die genauen Typen in diesem Fall nicht übereinstimmen mit null-Werte zulässt, meine Vermutung ist, is/as zu tun haben zusätzliche heavylifting hier auf, sicherzustellen, dass es ist in der Tat eine Instanz von Nullable-Typ.

    Und mal ehrlich: was macht Ihr is Nullable<xxx> plus HasValue kaufen Sie? Nichts. Sie können immer direkt auf der zugrunde liegenden (Wert -) Typ (in diesem Fall). Sie erhalten entweder den Wert, oder „Nein, nicht eine Instanz des Typs, den Sie forderten“. Auch wenn Sie schrieb (int?)null auf das array, der Typ check wird false zurückgegeben.

    Interessant… die Idee mit dem „wie“ + HasValue (nicht ist plus HasValue, Anm.) ist, dass es nur die Durchführung der Typ-check einmal statt zweimal. Dabei geht es um das „prüfen und unbox“ in einem einzigen Schritt. Das fühlt sich an wie es sollte schneller sein… aber es ist eindeutig nicht. Ich bin mir nicht sicher, was du meinst mit dem letzten Satz, aber es gibt keine solche Sache wie ein boxed int? – wenn Sie die box ein int? Wert es endet als ein boxed int oder ein null Referenz.

    InformationsquelleAutor dalo

  9. 8

    In Ordnung zu halten, diese Antwort ist up-to-date, es ist erwähnenswert, dass die meisten die Diskussion auf dieser Seite ist nun moot jetzt mit C# 7.1 und .NETTO 4.7 unterstützt ein slim-syntax, die auch produziert die besten IL-code.

    Den OP ‚ s original-Beispiel…

    object o = ...;
    int? x = o as int?;
    if (x.HasValue)
    {
    //...use x.Value in here
    }

    wird einfach…

    if (o is int x)
    {
    //...use x in here
    }

    Habe ich festgestellt, dass eine häufige Verwendung für die neue syntax ist beim schreiben ein .NET Wert Typ (d.h. struct im C#), die IEquatable<MyStruct> (die meisten sollten). Nach der Umsetzung des stark-typisierte Equals(MyStruct other) – Methode können Sie nun, anmutig umleiten der nicht typisierte Equals(Object obj) überschreiben (geerbt von Object) wie folgt:

    public override bool Equals(Object obj) => obj is MyStruct o && Equals(o);

     


    Anhang: Die Release bauen IL code für die ersten zwei Beispiel-Funktionen, siehe oben, in dieser Antwort (beziehungsweise) sind hier gegeben. Während der IL-code für die neue syntax ist in der Tat 1 byte kleiner ist, ist es meistens gewinnt big, indem Sie keine Anrufe (vs. zwei) und die Vermeidung der unbox Betrieb insgesamt, wenn möglich.

    //static void test1(Object o, ref int y)
    //{
    //    int? x = o as int?;
    //    if (x.HasValue)
    //        y = x.Value;
    //}
    [0] valuetype [mscorlib]Nullable`1<int32> x
    ldarg.0
    isinst [mscorlib]Nullable`1<int32>
    unbox.any [mscorlib]Nullable`1<int32>
    stloc.0
    ldloca.s x
    call instance bool [mscorlib]Nullable`1<int32>::get_HasValue()
    brfalse.s L_001e
    ldarg.1
    ldloca.s x
    call instance !0 [mscorlib]Nullable`1<int32>::get_Value()
    stind.i4
    L_001e: ret

    //static void test2(Object o, ref int y)
    //{
    //    if (o is int x)
    //        y = x;
    //}
    [0] int32 x,
    [1] object obj2
    ldarg.0
    stloc.1
    ldloc.1
    isinst int32
    ldnull
    cgt.un
    dup
    brtrue.s L_0011
    ldc.i4.0
    br.s L_0017
    L_0011: ldloc.1
    unbox.any int32
    L_0017: stloc.0
    brfalse.s L_001d
    ldarg.1
    ldloc.0
    stind.i4
    L_001d: ret

    Zur weiteren Prüfung, das untermauert meine Bemerkung über die Leistung der neuen C#7 syntax übertrifft die bisher verfügbaren Optionen finden Sie unter hier (insbesondere, Beispiel ‚D‘).

    InformationsquelleAutor Glenn Slayden

  10. 7
    using System;
    using System.Diagnostics;
    using System.Linq;
    class Test
    {
    const int Size = 30000000;
    static void Main()
    {
    object[] values = new object[Size];
    for (int i = 0; i < Size - 2; i += 3)
    {
    values[i] = null;
    values[i + 1] = "";
    values[i + 2] = 1;
    }
    FindSumWithCast(values);
    FindSumWithAsAndHas(values);
    FindSumWithAsAndIs(values);
    FindSumWithIsThenAs(values);
    FindSumWithIsThenConvert(values);
    FindSumWithLinq(values);
    Console.ReadLine();
    }
    static void FindSumWithCast(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    if (o is int)
    {
    int x = (int)o;
    sum += x;
    }
    }
    sw.Stop();
    Console.WriteLine("Cast: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithAsAndHas(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    int? x = o as int?;
    if (x.HasValue)
    {
    sum += x.Value;
    }
    }
    sw.Stop();
    Console.WriteLine("As and Has: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithAsAndIs(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    int? x = o as int?;
    if (o is int)
    {
    sum += x.Value;
    }
    }
    sw.Stop();
    Console.WriteLine("As and Is: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithIsThenAs(object[] values)
    {
    //Apple-to-apple comparison with Cast routine above.
    //Using the similar steps in Cast routine above,
    //the AS here cannot be slower than Linq.
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
    if (o is int)
    {
    int? x = o as int?;
    sum += x.Value;
    }
    }
    sw.Stop();
    Console.WriteLine("Is then As: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithIsThenConvert(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {            
    if (o is int)
    {
    int x = Convert.ToInt32(o);
    sum += x;
    }
    }
    sw.Stop();
    Console.WriteLine("Is then Convert: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    static void FindSumWithLinq(object[] values)
    {
    Stopwatch sw = Stopwatch.StartNew();
    int sum = values.OfType<int>().Sum();
    sw.Stop();
    Console.WriteLine("LINQ: {0} : {1}", sum,
    (long)sw.ElapsedMilliseconds);
    }
    }

    Ausgänge:

    Cast: 10000000 : 456
    As and Has: 10000000 : 2103
    As and Is: 10000000 : 2029
    Is then As: 10000000 : 1376
    Is then Convert: 10000000 : 566
    LINQ: 10000000 : 1811

    [EDIT: 2010-06-19]

    Hinweis: der Bisherige test wurde gemacht, innen VS, Konfiguration, debug, mit VS2009, mit Core i7(Unternehmens-Entwicklung-Maschine).

    Wurde Folgendes gemacht auf meinem Rechner mit Core 2 Duo, mit VS2010

    Inside VS, Configuration: Debug
    Cast: 10000000 : 309
    As and Has: 10000000 : 3322
    As and Is: 10000000 : 3249
    Is then As: 10000000 : 1926
    Is then Convert: 10000000 : 410
    LINQ: 10000000 : 2018
    Outside VS, Configuration: Debug
    Cast: 10000000 : 303
    As and Has: 10000000 : 3314
    As and Is: 10000000 : 3230
    Is then As: 10000000 : 1942
    Is then Convert: 10000000 : 418
    LINQ: 10000000 : 1944
    Inside VS, Configuration: Release
    Cast: 10000000 : 305
    As and Has: 10000000 : 3327
    As and Is: 10000000 : 3265
    Is then As: 10000000 : 1942
    Is then Convert: 10000000 : 414
    LINQ: 10000000 : 1932
    Outside VS, Configuration: Release
    Cast: 10000000 : 301
    As and Has: 10000000 : 3274
    As and Is: 10000000 : 3240
    Is then As: 10000000 : 1904
    Is then Convert: 10000000 : 414
    LINQ: 10000000 : 1936
    Welche framework-version verwenden Sie, aus Interesse? Die Ergebnisse auf meinem netbook (mithilfe .NET, 4RC) sind noch dramatischer – die Versionen mit Als viel schlimmer als Ihre Ergebnisse. Vielleicht haben Sie es verbessert .NET 4 RTM? Ich denke immer noch, es könnte schneller sein…
    Ich bin mit .NET 3.5 Framework
    Haben Sie ausgeführt, ein unoptimised bauen, oder läuft in den debugger?
    nicht optimierte bauen, unter einem debugger
    Recht – ich Neige zu der Ansicht der performance-Ergebnisse, die unter einem debugger als weitgehend irrelevant 🙂

    InformationsquelleAutor Michael Buen

Kostenlose Online-Tests

Letzte Fragen

Tun ItemView löst Blase?

Ich habe eine CompositeView für eine Tabelle. Ich habe Trigger-set in der Kind-ItemView für jede Zeile... var TableRow = Marionette.ItemView.extend({ tagName:...

Wie kann ich untersuchen, WCF was 400 bad request über GET?

Die folgenden WCF-endpoint funktioniert gut mit dem WCF test client: AssetList ListFlaggedAssets(short processCode, string platform, string endpoint = "null", string portalId = "null", int...

Bei der Verwendung von UUIDs, sollte ich auch mit AUTO_INCREMENT?

Wir bauen eine neue web-app, die eine offline-iPad - /Android-app-version auf einer Reihe von lokalen Geräten, die Einsätze mit neuen Daten. Als solche benötigen...

Actionscript-Objekt, das verschiedene Eigenschaften

Wie kann ich die Anzahl der Eigenschaften in einer generischen Actionscript-Objekt? (Wie die Array-Länge) InformationsquelleAutor Fragsworth | 2011-01-15

Wie plot mehrere Graphen und nutzen Sie die Navigations-Taste im [matplotlib]

Die neueste version von matplotlib erstellt automatisch Navigations-buttons unter den graph. Aber die Beispiele, die ich finden alles im Internet zeigen, wie erstellen Sie...