【发布时间】:2012-06-14 12:21:06
【问题描述】:
我知道 IQueryable 和 IEnumerable 之间的区别,并且我知道 Linq To Objects 通过 IEnumerable 接口支持集合。
让我感到困惑的是,当集合转换为 IQueryable 时,查询的执行速度是原来的两倍。
让 l 为 List 类型的填充对象,如果将列表 l 转换为IQueryable 通过 l.AsQueryable()。
我用 VS2010SP1 和 .NET 4.0 编写了一个简单的测试来证明这一点:
private void Test()
{
const int numTests = 1;
const int size = 1000 * 1000;
var l = new List<int>();
var resTimesEnumerable = new List<long>();
var resTimesQueryable = new List<long>();
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
for ( int x=0; x<size; x++ )
{
l.Add( x );
}
Console.WriteLine( "Testdata size: {0} numbers", size );
Console.WriteLine( "Testdata iterations: {0}", numTests );
for ( int n = 0; n < numTests; n++ )
{
sw.Restart();
var result = from i in l.AsEnumerable() where (i % 10) == 0 && (i % 3) != 0 select i;
result.ToList();
sw.Stop();
resTimesEnumerable.Add( sw.ElapsedMilliseconds );
}
Console.WriteLine( "TestEnumerable" );
Console.WriteLine( " Min: {0}", Enumerable.Min( resTimesEnumerable ) );
Console.WriteLine( " Max: {0}", Enumerable.Max( resTimesEnumerable ) );
Console.WriteLine( " Avg: {0}", Enumerable.Average( resTimesEnumerable ) );
for ( int n = 0; n < numTests; n++ )
{
sw.Restart();
var result = from i in l.AsQueryable() where (i % 10) == 0 && (i % 3) != 0 select i;
result.ToList();
sw.Stop();
resTimesQueryable.Add( sw.ElapsedMilliseconds );
}
Console.WriteLine( "TestQuerable" );
Console.WriteLine( " Min: {0}", Enumerable.Min( resTimesQueryable ) );
Console.WriteLine( " Max: {0}", Enumerable.Max( resTimesQueryable ) );
Console.WriteLine( " Avg: {0}", Enumerable.Average( resTimesQueryable ) );
}
运行此测试(使用 will numTests == 1 和 10)会产生以下输出:
Testdata size: 1000000 numbers
Testdata iterations: 1
TestEnumerable
Min: 44
Max: 44
Avg: 44
TestQuerable
Min: 37
Max: 37
Avg: 37
Testdata size: 1000000 numbers
Testdata iterations: 10
TestEnumerable
Min: 22
Max: 29
Avg: 23,9
TestQuerable
Min: 12
Max: 22
Avg: 13,9
重复测试但切换顺序(即先测量 IQuerable,然后测量 IEnumerable)会得到不同的结果!
Testdata size: 1000000 numbers
Testdata iterations: 1
TestQuerable
Min: 75
Max: 75
Avg: 75
TestEnumerable
Min: 25
Max: 25
Avg: 25
Testdata size: 1000000 numbers
Testdata iterations: 10
TestQuerable
Min: 12
Max: 28
Avg: 14
TestEnumerable
Min: 22
Max: 26
Avg: 23,4
这是我的问题:
- 我做错了什么?
- 如果在 IQueryable 测试之后执行测试,为什么 IEnumerable 更快?
- 为什么 IQueryable 在否时更快。测试运行次数增加?
- 使用 IQueryable 代替 IEnumerable 是否会受到惩罚?
我问这些问题是因为我想知道将哪一个用于我的存储库接口。现在他们查询内存中的集合(Linq to Objects),但在未来这可能是一个 SQL 数据源。如果我现在使用 IQueryable 设计存储库类,我以后可以轻松地切换到 Linq to SQL。但是,如果涉及性能损失,那么在不涉及 SQL 的情况下坚持使用 IEnumerable 似乎更明智。
【问题讨论】:
-
您没有指定是在发布模式还是调试模式下构建,并且您没有首先“启动”功能,因此您可能会看到抖动噪音。 (我想)。从长远来看,在 10,000,000 次迭代中相差几毫秒似乎并不是什么大问题。
-
我在调试模式下构建。切换到发布模式并添加“初始化”运行(即执行和具体化每个查询一次)确实有帮助:现在 IEnumerable 代码的执行速度比 IQueryable 代码稍快(11ms与 12 毫秒)。这正是我所期望的。所以我的测试代码有问题。感谢您的提示!
-
“我以后可以轻松切换到 Linq to SQL”...我很想听听你的效果如何。
标签: performance linq ienumerable linq-to-objects iqueryable