Сюрприз производительности с «как» и обнуляемыми типами
я просто пересматриваю главу 4 C # в глубине, которая имеет дело с обнуляемыми типами, и ядобавив раздел об использовании "как" оператор, который позволяет написать:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Я думал, что это действительно здорово, и что это может улучшить производительность по сравнению с эквивалентом C # 1, используя "является" с последующим приведением - в конце концов, таким образом, нам нужно только один раз запросить динамическую проверку типа, а затем простую проверку значения.
Однако, похоже, это не так. Я'ниже мы включили пример тестового приложения, которое в основном суммирует все целые числа в массиве объектов, но массив содержит множество пустых ссылок и ссылок на строки, а также целочисленные значения в штучной упаковке. Тест измеряет код, который выЯ должен использовать в C # 1, код с использованием "как" оператор, и просто для пинков решение LINQ. К моему удивлению, код C # 1 в этом случае работает в 20 раз быстрее - и даже код LINQ (который яя ожидал, что будет медленнее, учитывая участие итераторов)как" код.
Является ли реализация .NETisinst
для обнуляемых типов просто очень медленно? Это дополнительныйunbox.any
что вызывает проблему? Есть ли другое объяснение этому? Сейчас я чувствую, что ямне придется включить предупреждение против использования этого в ситуациях, чувствительных к производительности ...
Результаты:
В ролях: 10000000: 121
As: 10000000: 2211
LINQ: 10000000: 2143
Код:
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().Sum();
sw.Stop();
Console.WriteLine("LINQ: {0} : {1}", sum,
(long) sw.ElapsedMilliseconds);
}
}