Подтвердить что ты не робот

Почему использование Func <> намного быстрее, чем использование ограничения new() для создателя общей последовательности

Рассмотрим следующий код...

В моих тестах для сборки RELEASE (не отладки!) x86 на компьютере под управлением Windows 7 x64 (Intel i7 3GHz) я получил следующие результаты:

CreateSequence() with new() took 00:00:00.9158071
CreateSequence() with creator() took 00:00:00.1383482

CreateSequence() with new() took 00:00:00.9198317
CreateSequence() with creator() took 00:00:00.1372920

CreateSequence() with new() took 00:00:00.9340462
CreateSequence() with creator() took 00:00:00.1447375

CreateSequence() with new() took 00:00:00.9344077
CreateSequence() with creator() took 00:00:00.1365162

Кажется, что использование Func < > для определения делегата для создания новых объектов более чем в 6 раз быстрее, чем вызов "нового T()" напрямую.

Я нахожу это немного неожиданным... Я предполагаю, что это связано с некоторой инкрустацией, сделанной Jitter, но я бы подумал, что она также сможет оптимизировать "новый T()".

Есть ли у кого есть объяснение?

Возможно, я ошибаюсь. (Я рассмотрел эффект, который может иметь сборщик мусора, но переупорядочивание кода и добавление GC.Collect() и т.д. Не сильно меняют результаты).

В любом случае, здесь код:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApplication6
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();

            int repeats =    100;
            int count   = 100000;

            for (int outer = 0; outer < 4; ++outer)
            {
                sw.Restart();

                for (int inner = 0; inner < repeats; ++inner)
                {
                    CreateSequence<object>(count).Count();
                }

                Console.WriteLine("CreateSequence() with new() took " + sw.Elapsed);
                sw.Restart();

                for (int inner = 0; inner < repeats; ++inner)
                {
                    CreateSequence(count, () => new object()).Count();
                }

                Console.WriteLine("CreateSequence() with creator() took " + sw.Elapsed);
                Console.WriteLine();
            }
        }

        public static IEnumerable<T> CreateSequence<T>(int n) where T: new()
        {
            for (int i = 0; i < n; ++i)
            {
                yield return new T();
            }
        }

        public static IEnumerable<T> CreateSequence<T>(int n, Func<T> creator)
        {
            for (int i = 0; i < n; ++i)
            {
                yield return creator();
            }
        }
    }
}
4b9b3361

Ответ 1

Ограничение new() гарантирует, что только что переданный тип имеет конструктор без параметров. Если вы на самом деле вызываете new T() (или независимо от вашего имени аргумента типа), он на самом деле делает это:

Activator.CreateInstance<T>();

который в своей основе использует отражение.