我突然对linq性能感到好奇,并进行了一些测试.
下面是我的测试代码,结果非常令人惊讶.
任何人都可以使用linq工作,为什么比TryOut慢?
Public class TestObject { .... .... //this class contain many members bool deleted; .... } class Program { public static ConcurrentDictionarytestDictionary = new ConcurrentDictionary (); static void Main(string[] args) { //testDictionary is initialized in ohter code and is likely to have 10000 elements. RandomTest(0); RandomTest(1); Console.ReadKey(); } static void RandomTest(int k) { int count = 10000; List randomId = new List (); Random rnd = new Random(); for (int i = 0; i < count; i++) { int randomNumber = rnd.Next(0, testDictionary.Count()); randomId.Add(testDictionary.ElementAt(randomNumber).key); } Stopwatch sw = new Stopwatch(); sw.Start(); if (k == 0) { for (int i = 0; i < count; i++) { var res = checkid(randomId[i]); } } else if (k == 1) { for (int i = 0; i < count; i++) { var res = checkid2(randomId[i]); } } sw.Stop(); Console.WriteLine("Elapsed time : " + sw.Elapsed); } static bool checkid(string id) { TestObject t; return !testDictionary.TryGetValue(id, out t) ? false : t.deleted ? false : true; } static bool checkid2(string id) { return testDictionary.Any(t => t.key == id && !t.Value.deleted)? true : false; }
我运行了这两个方法10000次,结果显示如下
对于checkid方法,它大多花了不到00:00:00.002.
对于checkid2方法,它主要在00:00:02.2和00:00:02.4之间进行.
这是一个巨大的差异.
这是因为checkid2方法也检查已删除的变量,即使key不等于Id,而checkid方法只有在找到相应的密钥时检查已删除的变量?
Dictionary.TryGetValue
正在使用散列来定位元素,因此它是一个O(1)操作.
Dictionary.Any
将遍历集合,试图找到一个匹配条件的集合.那是O(n).
一般来说 - LINQ比使用for
/ 的手工制作循环要慢一点foreach
,但在大多数情况下性能差异并不重要.你所经历的不是LINQ在这里很慢,它的Dictionary
速度很快,因为它的内部结构被优化用于基于密钥的搜索.如果你改变它确实是一个List
并写一个for
循环来以线性方式进行相同的搜索(就像LINQ一样)你会看到差异变小了.