Какое выражение LINQ быстрее - PullRequest
0 голосов
/ 06 января 2011

Привет всем

В следующем коде

public class Person
{
    public string Name { get; set; }
    public uint Age { get; set; }

    public Person(string name, uint age)
    {
        Name = name;
        Age = age;
    }
}

void Main()
{
    var data = new List<Person>{ new Person("Bill Gates", 55), 
                                new Person("Steve Ballmer", 54), 
                                new Person("Steve Jobs", 55), 
                                new Person("Scott Gu", 35)};

    // 1st approach
    data.Where (x => x.Age > 40).ToList().ForEach(x => x.Age++);

    // 2nd approach
    data.ForEach(x => 
                    {
                        if (x.Age > 40)
                            x.Age++;
                    });

    data.ForEach(x => Console.WriteLine(x));    
}

в моем понимании 2-й подход должен быть более быстрым, поскольку он повторяет каждый элемент один раз, а первый подход выполняется 2времена:

  1. Где предложение
  2. ForEach для подмножества элементов из предложения where.

Однако внутренне может случиться так, что компилятор переводит 1-й подход во 2-йв любом случае, и они будут иметь одинаковую производительность.

Любые предложения или идеи?

Я мог бы сделать профилирование, как предложено, но я хочу понять, что происходит на уровне компилятора, если они в строкахкод одинаков для компилятора, иначе компилятор будет относиться к нему буквально.

Заранее спасибо за помощь.

Ответы [ 5 ]

3 голосов
/ 06 января 2011

Я только что запустил код, а вторая работает быстрее:

static void T3()
        {
            var data = new List<Person>{ new Person("Bill Gates", 55), 
                                new Person("Steve Ballmer", 54), 
                                new Person("Steve Jobs", 55), 
                                new Person("Scott Gu", 35)};

            System.Diagnostics.Stopwatch s1 = new System.Diagnostics.Stopwatch();

            s1.Start();
            // 1st approach
            data.Where(x => x.Age > 40).ToList().ForEach(x => x.Age++);
            s1.Stop();

            System.Diagnostics.Stopwatch s2 = new System.Diagnostics.Stopwatch();

            s2.Start();
            // 2nd approach
            data.ForEach(x =>
            {
                if (x.Age > 40)
                    x.Age++;
            });
            s2.Stop();

            Console.Write("s1: " + s1.ElapsedTicks + " S2:" + s2.ElapsedTicks);
            data.ForEach(x => Console.WriteLine(x));
        }

Этого и следовало ожидать, поскольку второй не нужно преобразовывать в список и затем запускать метод foreach.

Результаты: с1: 1192 С2: 255

2 голосов
/ 07 января 2011

Вы выступаете против .Where() без измерения. Реальная разница между этими двумя подходами заключается в .ToList().

3-й подход:

foreach(Person x in data.Where(x => x.Age > 40))
{
  x.Age++; 
}
1 голос
/ 06 января 2011

Я считаю, что первый будет медленным из-за ToList(). Создание новой структуры данных должно быть относительно медленным.

1 голос
/ 06 января 2011

Вставьте код в LinqPad (www.linqpad.net) и установите время. Или вы можете проверить сгенерированный код IL, чтобы увидеть, как его обрабатывает компилятор.

0 голосов
/ 06 января 2011

Если вам интересно, как компилятор обрабатывает эти два выражения, почему бы не скомпилировать каждое из них, а затем использовать инструмент ildasm (в комплекте с Visual Studio) для просмотра сгенерированного кода?

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