Производительность IEnumerable <T>.Count () - разница между итерацией по типам значений и ссылочным типам - PullRequest
0 голосов
/ 26 мая 2020

Я пытаюсь оптимизировать подсчет элементов в коллекции (IEnumerable<T>)

Поскольку эти данные загружаются из кеша в памяти, нет смысла переключаться на использование IQueryable<T>.Count() (чтобы было просто вызов базы данных SELECT count(1) FROM TableT вместо перебора всего списка IEnumerable<T>)

Итак, у меня просто возникла идея, что, возможно, итерация коллекции (IEnumerable) типа значения (например, int) может быть быстрее, чем итерация по коллекция ссылочного типа

myEnumerable.Count();

заменена на это:

myEnumerable.Select(el => el.Id).Count();

Не знаю, правда ли это, и не знаю, как протестируйте его правильно, но первые простые оценки показывают, что итерация по IEnumerable<int> немного быстрее (например, на 5-10%), чем итерация по IEnumerable<some-business-object>

Итак, вопрос в том, есть ли разница для итерации по коллекции содержит ли коллекция типы значений или ссылочные типы?

1 Ответ

2 голосов
/ 26 мая 2020

myEnumerable.Count ();

заменяется на это:

myEnumerable.Select (el => el.Id) .Count ();

Это определенно падение производительности! Я не знаю, как вы сравниваете те, которые пришли к выводу, что это лучше, но вы можете легко сравнить их следующим образом:

class TestObj
{
    public int Id { get; set; }
}

static void Main(string[] args)
{
    var dataRef = Enumerable.Empty<TestObj>();
    for (int i = 0; i < 100000; i++)
    {
        dataRef = dataRef.Append(new TestObj { Id = i });
    }

    var sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < 100000; i++)
    {
        dataRef.Count();
    }
    sw.Stop();
    Console.WriteLine($"By Ref: {sw.ElapsedMilliseconds / 1000.0} Sec");

    sw.Restart();
    var dataVal = dataRef.Select(p => p.Id);
    for (int i = 0; i < 100000; i++)
    {
        dataVal.Count();
    }
    Console.WriteLine($"By Val: {sw.ElapsedMilliseconds / 1000.0} Sec");
}

Результаты:

By Ref: 0.002 Sec
By Val: 4.111 Sec

Обычно ValueType и ReferenceType если мы рассматриваем их независимо как два перечислимых, не будет существенных различий во времени итерации и подсчете. Но то, что вы сделали выше, - это добавление перечисления к перечисляемому ссылочному типу, чтобы преобразовать его в перечислимый тип значения, что приводит к большим накладным расходам и снижению производительности. Стоимость по памяти, вы можете использовать .ToList(), и тогда .Count() будет близка к нулю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...