Я думал, что я мог бы звонить здесь ...
Хотя я согласен Неизменяемые структуры имеют смысл во многих ситуациях, но удобство чтения и обслуживания всегда должны учитывать ваши соображения. Если ваша цель - производительность, то создание новой структуры в Linq Select
не складывается (в этой ситуации). Вы просто выполняете больше выделений и создаете больше мусора.
В любой нормальной ситуации это, вероятно, не имеет значения. Однако, «если» вы заинтересованы в производительности и у вас есть инструкция и цикл OCD , то я бы рассмотрел альтернативные варианты и оценил бы ваши решения.
Учитывая следующие 3 метода
public void ByRef(ref Rect entity)
{
if (entity.Y + entity.Height > 800)
{
entity.Y++;
}
}
public Rect ByImutableReturn(Rect entity)
{
return entity.Y + entity.Height > 800 ? new Rect(entity.Height, entity.Y + 1) : entity;
}
public Rect ByReturn(Rect entity)
{
if (entity.Y + entity.Height > 800)
{
entity.Y++;
}
return entity;
}
LinqImutableReturn
protected override List<Rect> InternalRun()
{
return Input.Cubes = Input.Cubes.Select(r => Input.ByImutableReturn(r))
.ToList();
}
LinqReturn
protected override List<Rect> InternalRun()
{
return Input.Cubes = Input.Cubes.Select(r => Input.ByReturn(r))
.ToList();
}
ForLoopByRef
protected override List<Rect> InternalRun()
{
for (var index = 0; index < Input.Cubes.Count; index++)
{
var t = Input.Cubes[index];
Input.ByRef(ref t);
Input.Cubes[index] = t;
}
return Input.Cubes.ToList();
}
ForLoopImutableReturn
protected override List<Rect> InternalRun()
{
for (var index = 0; index < Input.Cubes.Count; index++)
{
Input.Cubes[index] = Input.ByImutableReturn(Input.Cubes[index]);
}
return Input.Cubes.ToList();
}
ForLoopReturn
protected override List<Rect> InternalRun()
{
for (var index = 0; index < Input.Cubes.Count; index++)
{
Input.Cubes[index] = Input.ByReturn(Input.Cubes[index]);
}
return Input.Cubes.ToList();
}
Результаты
Mode : Release
Test Framework : .NET Framework 4.7.1
Benchmarks runs : 100 times (averaged/scale)
Scale : 10,000
Name | Time | Range | StdDev | Cycles
--------------------------------------------------------------------------
ForLoopByRef | 0.073 ms | 0.001 ms | 0.07 | 244,964
ForLoopReturn | 0.097 ms | 0.006 ms | 0.05 | 332,372
ForLoopImutableReturn | 0.116 ms | 0.003 ms | 0.08 | 388,188
LinqImutableReturn | 0.325 ms | 0.007 ms | 0.25 | 1,117,130
LinqReturn | 0.347 ms | 0.002 ms | 0.07 | 1,195,351
Scale : 100,000
Name | Time | Range | StdDev | Cycles
---------------------------------------------------------------------------
ForLoopByRef | 0.635 ms | 0.168 ms | 0.11 | 2,215,066
ForLoopImutableReturn | 0.867 ms | 0.175 ms | 0.10 | 3,027,096
ForLoopReturn | 0.890 ms | 0.225 ms | 0.09 | 3,109,831
LinqReturn | 2.957 ms | 0.166 ms | 0.17 | 10,347,672
LinqImutableReturn | 3.084 ms | 0.219 ms | 0.40 | 10,780,304
Scale : 1,000,000
Name | Time | Range | StdDev | Cycles
-----------------------------------------------------------------------------
ForLoopByRef | 6.624 ms | 1.685 ms | 0.83 | 23,156,409
ForLoopImutableReturn | 9.574 ms | 1.678 ms | 0.82 | 33,503,375
ForLoopReturn | 9.811 ms | 2.290 ms | 0.86 | 34,324,963
LinqImutableReturn | 32.463 ms | 1.401 ms | 1.11 | 113,246,111
LinqReturn | 32.973 ms | 0.830 ms | 1.18 | 114,892,311
Резюме
Я бы взял эти результаты с крошкой соли. Вещи не так чисты, когда вы смотрите на высокопроизводительный код. Но мораль этой истории в том, что если вы стремитесь к производительности, а не к удобству чтения и обслуживания, вам нужно тестировать код в реальных ситуациях.