Является ли оператор LINQ быстрее, чем цикл foreach?

Я пишу менеджер Mesh Rendering и думал, что было бы неплохо сгруппировать все ячейки, которые используют один и тот же шейдер, а затем визуализировать их, пока я нахожусь в этом шейдерном проходе.

В настоящее время я использую цикл foreach, но задавался вопросом, может ли использование LINQ увеличить производительность?

Ответы

Ответ 1

Почему LINQ будет быстрее? Он также использует петли внутри.

В большинстве случаев LINQ будет немного медленнее, потому что он вводит накладные расходы. Не используйте LINQ, если вы заботитесь о производительности. Используйте LINQ, потому что вам нужен более удобный для чтения и поддерживаемый код.

Ответ 2

LINQ-to-Objects обычно добавляет некоторые предельные накладные расходы (несколько итераторов и т.д.). Он по-прежнему должен делать циклы и имеет делегировать вызовы и обычно должен выполнять некоторые дополнительные разыгрывания, чтобы получить захваченные переменные и т.д. В большинстве кодов это будет практически невозможно обнаружить и более чем доступно более простому пониманию кода.

С другими поставщиками LINQ, такими как LINQ-to-SQL, тогда, поскольку запрос может фильтроваться на сервере, он должен быть намного лучше, чем плоский foreach, но, скорее всего, вы бы не сделали одеяло "select * from foo" в любом случае, так что это не обязательно справедливое сравнение.

Re PLINQ; parallelism может сократить прошедшее время, но общее время процессора обычно немного увеличивается из-за накладных расходов на управление потоками и т.д.

Ответ 3

Я думаю, что LINQ лучше использовать в цикле foreach, потому что он дает вам гораздо более чистый и понятный код. Но LINQ медленнее, чем foreach. Чтобы получить больше, просмотрите статью LINQ vs FOREACH vs FOR Loop Performance.

Ответ 4

LINQ работает медленнее, но в какой-то момент он может ускориться. Хорошая вещь о LINQ заключается в том, что вам не нужно заботиться о том, как это работает. Если новый метод считается невероятно быстрым, люди в Microsoft могут реализовать его, даже не сообщая вам, и ваш код будет намного быстрее.

Более того, LINQ гораздо проще читать. Этого должно быть достаточно.

Ответ 5

Вы можете повысить производительность, если используете параллельные LINQ для нескольких ядер. См. Параллельный LINQ (PLINQ) (MSDN).

Ответ 6

Следует, наверное, отметить, что цикл for быстрее, чем foreach. Поэтому для исходного сообщения, если вас беспокоит производительность на критическом компоненте, например рендерере, используйте цикл for.

Ссылка: В .NET, какой цикл работает быстрее, 'for' или 'foreach'?

Ответ 7

Мне был интересен этот вопрос, поэтому я сделал тест только сейчас. Использование .NET Framework 4.5.2 на процессоре i3-2328M с процессором Intel (R) Core i3-2328M с частотой 2,20 ГГц, 2200 МГц, 2 ядрами с 8 ГБ оперативной памяти, работающей под управлением Microsoft Windows 7 Ultimate.

Похоже, что LINQ может быть быстрее, чем для каждого цикла. Вот результаты, которые я получил:

Exists=True
Time=174
Exists=True
Time=149

Было бы интересно, если бы некоторые из вас могли скопировать и вставить этот код в консольное приложение и протестировать. Перед тестированием с объектом (Employee) я попробовал один и тот же тест с целыми числами. LINQ был быстрее там.

public class Program
{

    public class Employee
    {
        public int id;
        public string name;
        public string lastname;
        public DateTime dateOfBirth;

        public Employee(int id,string name,string lastname,DateTime dateOfBirth)
        {
            this.id = id;
            this.name = name;
            this.lastname = lastname;
            this.dateOfBirth = dateOfBirth;

        }

    }

    public static void Main()
    {

        StartObjTest();
    }

    #region object test

    public static void StartObjTest()
    {
        List<Employee> items = new List<Employee>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(new Employee(i,"name" + i,"lastname" + i,DateTime.Today));
        }

        Test3(items, items.Count-100);
        Test4(items, items.Count - 100);

        Console.Read();
    }


    public static void Test3(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item.id == idToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test4(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Exists(e => e.id == idToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion


    #region int test
    public static void StartIntTest()
    {
        List<int> items = new List<int>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(i);
        }

        Test1(items, -100);
        Test2(items, -100);

        Console.Read();
    }

    public static void Test1(List<int> items,int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item == itemToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test2(List<int> items, int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Contains(itemToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion

}

Ответ 8

Это довольно сложный вопрос. Linq делает некоторые вещи очень простыми, что если вы их сами реализуете, вы можете наткнуться (например, linq.Except()). Это особенно относится к PLinq, и особенно к параллельной агрегации, реализованной PLinq.

В общем случае для идентичного кода linq будет медленнее из-за накладных расходов на вызов делегата.

Если, однако, вы обрабатываете большой массив данных и применяете относительно простые вычисления к элементам, вы получите огромное увеличение производительности, если:

  • Вы используете массив для хранения данных.
  • Вы используете цикл for для доступа к каждому элементу (в отличие от foreach или linq).

    • Примечание. При тестировании, пожалуйста, помните, что если вы используете один и тот же массив/список для двух последовательных тестов, кэш CPU сделает второй быстрее. *