Find() 与 FirstOrDefault() 的性能 [英] Performance of Find() vs. FirstOrDefault()
问题描述
类似问题:
使用可枚举模式.看看这张图
.
我点击了 foreach 来查看它在做什么,你可以看到 dotpeek 想要带我到 enumerator/current/next 实现,这是有道理的.
除此之外它们基本相同(测试传入的谓词以查看某个项目是否是您想要的)
Similar Question:
Find() vs. Where().FirstOrDefault()
Got an interesting outcome searching for Diana within a large sequence of a simple reference type having a single string property.
using System;
using System.Collections.Generic;
using System.Linq;
public class Customer{
public string Name {get;set;}
}
Stopwatch watch = new Stopwatch();
const string diana = "Diana";
while (Console.ReadKey().Key != ConsoleKey.Escape)
{
//Armour with 1000k++ customers. Wow, should be a product with a great success! :)
var customers = (from i in Enumerable.Range(0, 1000000)
select new Customer
{
Name = Guid.NewGuid().ToString()
}).ToList();
customers.Insert(999000, new Customer { Name = diana }); // Putting Diana at the end :)
//1. System.Linq.Enumerable.DefaultOrFirst()
watch.Restart();
customers.FirstOrDefault(c => c.Name == diana);
watch.Stop();
Console.WriteLine("Diana was found in {0} ms with System.Linq.Enumerable.FirstOrDefault().", watch.ElapsedMilliseconds);
//2. System.Collections.Generic.List<T>.Find()
watch.Restart();
customers.Find(c => c.Name == diana);
watch.Stop();
Console.WriteLine("Diana was found in {0} ms with System.Collections.Generic.List<T>.Find().", watch.ElapsedMilliseconds);
}
Is this because of no Enumerator overhead in List.Find() or this plus maybe something else?
Find()
runs almost as twice as faster, hoping .Net team will not mark it Obsolete in the future.
I was able to mimic your results so I decompiled your program and there is a difference between Find
and FirstOrDefault
.
First off here is the decompiled program. I made your data object an anonmyous data item just for compilation
List<u003Cu003Ef__AnonymousType0<string>> source = Enumerable.ToList(Enumerable.Select(Enumerable.Range(0, 1000000), i =>
{
var local_0 = new
{
Name = Guid.NewGuid().ToString()
};
return local_0;
}));
source.Insert(999000, new
{
Name = diana
});
stopwatch.Restart();
Enumerable.FirstOrDefault(source, c => c.Name == diana);
stopwatch.Stop();
Console.WriteLine("Diana was found in {0} ms with System.Linq.Enumerable.FirstOrDefault().", (object) stopwatch.ElapsedMilliseconds);
stopwatch.Restart();
source.Find(c => c.Name == diana);
stopwatch.Stop();
Console.WriteLine("Diana was found in {0} ms with System.Collections.Generic.List<T>.Find().", (object) stopwatch.ElapsedMilliseconds);
The key thing to notice here is that FirstOrDefault
is called on Enumerable
whereas Find
is called as a method on the source list.
So, what is find doing? This is the decompiled Find
method
private T[] _items;
[__DynamicallyInvokable]
public T Find(Predicate<T> match)
{
if (match == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
for (int index = 0; index < this._size; ++index)
{
if (match(this._items[index]))
return this._items[index];
}
return default (T);
}
So it's iterating over an array of items which makes sense, since a list is a wrapper on an array.
However, FirstOrDefault
, on the Enumerable
class, uses foreach
to iterate the items. This uses an iterator to the list and move next. I think what you are seeing is the overhead of the iterator
[__DynamicallyInvokable]
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
throw Error.ArgumentNull("source");
if (predicate == null)
throw Error.ArgumentNull("predicate");
foreach (TSource source1 in source)
{
if (predicate(source1))
return source1;
}
return default (TSource);
}
Foreach is just syntatic sugar on using the enumerable pattern. Look at this image
.
I clicked on foreach to see what it's doing and you can see dotpeek wants to take me to the enumerator/current/next implementations which makes sense.
Other than that they are basically the same (testing the passed in predicate to see if an item is what you want)
这篇关于Find() 与 FirstOrDefault() 的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!