Редактировать: По предложению DavidG я увеличил количество предметов в 100 раз.Я перезапустил сравнение в режиме релиза и обновил результаты ниже.Я также обновил код на тот случай, если кто-то просто скопирует, вставит и запустит его локально.
Так что я видел много публикаций на SO о LINQ против производительности for
-большинству из которых уже несколько лет - и я хотел увидеть это в действии для себя.Поэтому я написал небольшое приложение для тестирования, и результаты оказались ... не совсем такими, как я ожидал. У меня вопрос: изменения и оптимизации в C # 6 сделали всю проблему производительности неактуальной?
(поскольку это была проблема вместо интересной микрооптимизации для большой частибаза пользователей .NET Интересно, да, но не то, что большинству людей действительно нужно беспокоиться.)
Я знаю, что все еще есть хорошие вопросы об использовании ручных циклов и LINQ изс точки зрения использования памяти, но либо мое приложение для сравнения имеет серьезные недостатки, либо кажется, что разница в скорости больше невелика.Возможно, он был оптимизирован в более поздних версиях C #?
Мое приложение ниже.Он придуман, я признаю - это наихудший сценарий, когда мы пытаемся найти предмет, который будет найден мертвым последним в списке из миллиона предметов, - но я взял его, основываясь на других сообщениях здесь.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace LinqDemo
{
class Program
{
static void Main(string[] args)
{
new Program().Run();
}
public void Run()
{
RunPerformanceComparison();
Console.ReadKey();
}
private void RunPerformanceComparison()
{
Func<string, bool> criteriaFunction = d => d.Equals("YES");
var data = new string[100000000];
for (int i = 0; i < data.Length - 1; i++)
{
data[i] = "NO";
}
data[data.Length - 1] = "YES";
Console.WriteLine("With LINQ");
Console.WriteLine("------------");
DoPerformanceRunLinq(data, criteriaFunction);
Console.WriteLine();
Console.WriteLine("Without LINQ");
Console.WriteLine("------------");
DoPerformanceRunManual(data, criteriaFunction);
}
private void DoPerformanceRunLinq(string[] data, Func<string, bool> criteriaFunction)
{
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 10; i++)
{
sw.Start();
var result = data.Where(criteriaFunction).Select(d => d).ToList();
sw.Stop();
Console.WriteLine($"Iteration {i + 1}\tElapsed: {sw.Elapsed.TotalMilliseconds.ToString("n2")} ms");
sw.Reset();
}
}
private void DoPerformanceRunManual(string[] data, Func<string, bool> criteriaFunction)
{
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 10; i++)
{
sw.Start();
var result = GetItems(data, criteriaFunction);
sw.Stop();
Console.WriteLine($"Iteration {i + 1}\tElapsed: {sw.Elapsed.TotalMilliseconds.ToString("n2")} ms");
sw.Reset();
}
}
private IEnumerable<string> GetItems(string[] data, Func<string, bool> criteriaFunction)
{
var ret = new List<string>();
// Not deferred; runs all at once
for (int i = 0; i < data.Length; i++)
{
if (criteriaFunction(data[i]))
{
ret.Add(data[i]);
}
}
return ret;
}
}
}
Вот результат выполнения этого (я запустил его в командной строке без VS):
With LINQ
------------
Iteration 1 Elapsed: 602.39 ms
Iteration 2 Elapsed: 522.72 ms
Iteration 3 Elapsed: 601.15 ms
Iteration 4 Elapsed: 518.71 ms
Iteration 5 Elapsed: 511.38 ms
Iteration 6 Elapsed: 565.92 ms
Iteration 7 Elapsed: 506.51 ms
Iteration 8 Elapsed: 524.91 ms
Iteration 9 Elapsed: 540.85 ms
Iteration 10 Elapsed: 502.33 ms
Without LINQ
------------
Iteration 1 Elapsed: 496.09 ms
Iteration 2 Elapsed: 496.15 ms
Iteration 3 Elapsed: 540.53 ms
Iteration 4 Elapsed: 549.28 ms
Iteration 5 Elapsed: 404.46 ms
Iteration 6 Elapsed: 407.23 ms
Iteration 7 Elapsed: 461.39 ms
Iteration 8 Elapsed: 414.90 ms
Iteration 9 Elapsed: 405.67 ms
Iteration 10 Elapsed: 437.98 ms
Более 100 миллионов строк, это лучшая производительность на стороне for
, но не значительными суммами, которые некоторые люди требовали в прошлом (я слышал, как разница в 10 раз. Это даже не близко).Плюс, это 100 миллионов строк в памяти - я не думаю, что оптимизация здесь будет сделана путем выбора ручных циклов против LINQ.:) На самом деле, я не уверен, что разница здесь достаточно велика для того, чтобы кого-либо действительно волновало, если только вам абсолютно не нужна каждая последняя микросекунда производительности.В общем, я бы назвал это стиркой.
Я где-то испортил свое приложение, это просто неверное сравнение, или что-то изменилось внутри .NET?