kus*_*men 6 .net c# linq performance benchmarking
所以, first(FirstOrDefault(predicate)) 一个在性能方面更好1
我明白了,我也认为再调用一个方法应该稍微慢一点,这只是我的直觉。尽管如此,我还是决定运行一些基准测试来证明我的权利,而我却知之甚少。
这是我运行基准测试的结果:
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
Intel Core i7-3630QM CPU 2.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.101
[Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
Job-XMZTSC : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT
Runtime=.NET 4.7.2
Method N Mean Error StdDev Ratio RatioSD
WherePlusFirstOrDefaultArray 10000 31.44 us 0.288 us 0.270 us 0.40 0.00
FirstOrDefaultArray 10000 78.47 us 0.679 us 0.635 us 1.00 0.00
WherePlusFirstOrDefaultList 10000 54.27 us 1.070 us 1.099 us 0.69 0.02
FirstOrDefaultList 10000 100.84 us 1.722 us 1.611 us 1.29 0.02
WherePlusFirstOrDefaultArray 100000 325.41 us 4.840 us 4.527 us 0.39 0.01
FirstOrDefaultArray 100000 829.85 us 16.513 us 15.446 us 1.00 0.00
WherePlusFirstOrDefaultList 100000 558.10 us 5.507 us 5.151 us 0.67 0.01
FirstOrDefaultList 100000 1,026.93 us 17.648 us 16.508 us 1.24 0.02
WherePlusFirstOrDefaultArray 1000000 3,255.46 us 9.615 us 7.507 us 0.40 0.01
FirstOrDefaultArray 1000000 8,134.15 us 108.425 us 101.420 us 1.00 0.00
WherePlusFirstOrDefaultList 1000000 5,477.63 us 70.584 us 66.024 us 0.67 0.01
FirstOrDefaultList 1000000 9,987.54 us 64.239 us 60.089 us 1.23 0.02
Run Code Online (Sandbox Code Playgroud)
不仅Where(predicate).FirstOrDefault()
速度更快,而且速度更快。
这是我的基准代码使用 BenchmarkDotNet
[SimpleJob(RuntimeMoniker.Net472)]
public class Benchmarks
{
private int[] _array;
private List<int> _list;
[Params(10000, 100000, 1000000)]
public int N;
[GlobalSetup]
public void Setup()
{
_array = new int[N];
_list = new List<int>(N);
_array = Enumerable
.Repeat(0, N - 1).ToArray();
_list = Enumerable
.Repeat(0, N - 1).ToList();
_array[N - 2] = 7;
_list[N - 2] = 7;
}
[Benchmark]
public int WherePlusFirstOrDefaultArray()
{
var seven = _array.Where(n => n == 7).FirstOrDefault();
return seven;
}
[Benchmark(Baseline = true)]
public int FirstOrDefaultArray()
{
var seven = _array.FirstOrDefault(n => n == 7);
return seven;
}
[Benchmark]
public int WherePlusFirstOrDefaultList()
{
var seven = _list.Where(n => n == 7).FirstOrDefault();
return seven;
}
[Benchmark]
public int FirstOrDefaultList()
{
var seven = _list.FirstOrDefault(n => n == 7);
return seven;
}
}
Run Code Online (Sandbox Code Playgroud)
由于我对结果感到震惊,让我别无选择,只能问你们我做错了什么还是我错过了什么?
编辑:
我向那些认为可能是因为List
.
EDIT2:传奇还在继续,我想我更接近答案了。将硬件计数器添加到我的基准测试中产生了以下有趣的结果:
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
Intel Core i7-3630QM CPU 2.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.101
[Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
Job-ZTIMEH : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT
Runtime=.NET 4.7.2
Method N Mean Error StdDev Ratio RatioSD CacheMisses/Op BranchMispredictions/Op
WherePlusFirstOrDefaultArray 1000000 3.222 ms 0.0224 ms 0.0210 ms 0.39 0.01 885 327
FirstOrDefaultArray 1000000 8.166 ms 0.1992 ms 0.1863 ms 1.00 0.00 1,795 810
WherePlusFirstOrDefaultList 1000000 5.564 ms 0.1066 ms 0.1228 ms 0.68 0.02 1,051 503
FirstOrDefaultList 1000000 10.161 ms 0.1816 ms 0.1699 ms 1.24 0.03 3,451 1,442
Run Code Online (Sandbox Code Playgroud)
出于某种原因,我仍然无法向自己解释为什么FirstOrDefault(predicate)
方法产生的分支错误预测和 ofc 缓存未命中是2 到 3 倍Where(predicate).FirstOrDefault()
,这肯定在我之前观察到的结果中起到了一定的作用。
此外,一个奇怪的事,如果你看看FirstOrDefaultArray
和FirstOrDefaultList
结果,并加以比较,你会看到该列表是24%速度较慢,但这些方法生成的程序集是相同的对我说:https://www.diffchecker.com/WSjAQlet(我剥指令的内存地址。)
泛型Enumerable.Where
函数根据参数的类型映射到不同的子类。在本例中,您的参数是 a ,因此您从带有参数的aList<int>
返回。然后它使用枚举器列表,返回 a ,它使用索引来索引并返回每个成员。这非常快。Where
Enumerable.WhereListIterator<int>
List<int>
List<T>.GetEnumerator()
List<T>.Enumerator
struct
List<>
FirstOrDefault(Func<> pred)
没有这个优化,用来foreach
遍历列表。虽然这最终也使用相同的非常快的List<T>.Enumerator
方法,但它通过接口调用其成员方法IEnumerable<T>
,这比直接调用方法要慢得多List<T>.Enumerator
。
我的测试表明,结果FirstOrDefault(Func<> pred)
大约是源列表中每个元素的两倍时间。FirstOrDefault<T>(List<T> src, Func<T,bool> pred)
如果您使用GetEnumerator
或编写自己的foreach
,它的运行速度大约是内置FirstOrDefault
.
归档时间: |
|
查看次数: |
188 次 |
最近记录: |