Типы значений и ссылочные типы — производительность

Я занят чтением отличной книги Джона Скита C# In Depth. В разделе о упаковке и распаковке он упоминает, что использование упакованных объектов имеет небольшие накладные расходы, которые могут повлиять на производительность в достаточно большом масштабе.

Поэтому я написал свои собственные тесты производительности, сложив вместе все числа от 1 до 100 000 000 с помощью цикла for. В одном случае я использовал Int32, затем int, затем я выполнил приведение к object и обратно к int. Повторил все тесты 10 раз и взял среднее. Результаты (в секундах):

Int32 в среднем: 0,333

среднее значение: 0,326

Объект в среднем: 1,061

Между Int32 и int особой разницы нет, но упаковка/распаковка заняла в 3 раза больше времени!

Поэтому, пожалуйста, помогите мне понять: когда вы приводите int к object, разве это не то же самое, что приводить его к Int32? DotNetPerls утверждает, что int на самом деле просто псевдоним для Int32, но если это так, тогда почему int постоянно работает быстрее, чем Int32, пусть даже незначительно?

EDIT: По многочисленным просьбам, вот код теста:

const int SIZE = 100000000, ITERATIONS=10;
var intTimes = new List<double>();
var int32Times = new List<double>();
var objectTimes = new List<double>();

for (var n = 0; n < ITERATIONS; n++)
{
    Console.WriteLine("Iteration "+(n+1));
    Console.WriteLine("Testing using Int32");
    long result = 0;
    var sw = Stopwatch.StartNew();
    for (Int32 x = 0; x < SIZE; x++)
    {
        result += x;
    }
    sw.Stop();
    int32Times.Add(sw.Elapsed.TotalSeconds);
    Console.WriteLine("Result = {0} after {1:0.000} seconds", result, sw.Elapsed.TotalSeconds);

    Console.WriteLine("Testing using int");
    result = 0;
    sw = Stopwatch.StartNew();
    for (int x = 0; x < SIZE; x++)
    {
        result += x;
    }
    sw.Stop();
    Console.WriteLine("Result = {0} after {1:0.000} seconds", result, sw.Elapsed.TotalSeconds);
    intTimes.Add(sw.Elapsed.TotalSeconds);

    Console.WriteLine("Testing using object");
    result = 0;
    sw = Stopwatch.StartNew();
    for (int i = 0; i < SIZE; i++)
    {
        object o = i;
        result += (int) o;
    }
    sw.Stop();
    Console.WriteLine("Result = {0} after {1:0.000} seconds", result, sw.Elapsed.TotalSeconds);
    objectTimes.Add(sw.Elapsed.TotalSeconds);
}
Console.WriteLine("Summary:");
Console.WriteLine("Int32 avg: {0:0.000}", int32Times.Average());
Console.WriteLine("int avg: {0:0.000}", intTimes.Average());
Console.WriteLine("object avg: {0:0.000}", objectTimes.Average());

person Shaul Behr    schedule 01.05.2013    source источник
comment
Мы должны увидеть ваши тесты. Скорее всего, вы не разогреваете джиттер, поэтому ваш первый будет работать медленнее, чем второй.   -  person Kirk Woll    schedule 01.05.2013
comment
Тестовый код @KirkWoll добавлен к вопросу.   -  person Shaul Behr    schedule 01.05.2013


Ответы (1)


Ключевое слово C# int является псевдонимом для System.Int32. Так что выступление точно такое же.

Конечно, во время измерения всегда возникают колебания, потому что ваша машина выполняет и другие задачи.

Каждый раз, когда вы приводите int к object, небольшой участок памяти (в куче) резервируется, и туда копируется значение int. Это требует некоторых усилий. Каждый раз, когда вы отбрасываете его обратно, .NET сначала проверяет, действительно ли ваш объект содержит int (поскольку объект может содержать что угодно), а затем копирует значение обратно в int. Эта проверка также требует времени.

person Martin Mulder    schedule 01.05.2013
comment
Я запускал тест несколько раз; каждый раз цикл int был быстрее, чем цикл Int32, между 1-5%. Думаешь, это было просто совпадение? - person Shaul Behr; 01.05.2013
comment
Это одна программа, которую вы запускаете, выполняя все три теста, или вы модифицируете программу и запускаете один тест для одного типа данных? - person Martin Mulder; 01.05.2013
comment
@Shaul Это должно быть совпадение (или ошибка в вашем тестовом коде). int и System.Int32 являются синонимами. Они будут создавать идентичный код IL (что можно проверить с помощью Reflector). - person Matthew Watson; 01.05.2013
comment
Интересно. Я поменял местами int и Int32 в тестовом цикле, и теперь Int32 немного быстрее. Итак, вы правы, это не связано с различием int и Int32, а скорее с некоторыми накладными расходами при запуске этого цикла. @MatthewWatson - вежливый пинг. - person Shaul Behr; 01.05.2013
comment
Потому и спрашивается. При первом запуске фрагмента кода в первый раз выполняются некоторые дополнительные операции, такие как загрузка сборок и т. д. Это также приведет к некоторой задержке. - person Martin Mulder; 01.05.2013