Performance-Überraschung mit "as" und NULL-fähigen 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.anydie 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:

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);
        FindSumWithAs(values);
        FindSumWithLinq(values);
    }

    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 FindSumWithAs(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: {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);
    }
}

InformationsquelleAutor der Frage Jon Skeet | 2009-10-17

Schreibe einen Kommentar