gpt4 book ai didi

performance - 为什么使用 Linq To Objects 时 IQueryable 比 IEnumerable 快两倍

转载 作者:行者123 更新时间:2023-12-04 12:11:20 27 4
gpt4 key购买 nike

我知道 IQueryable 和 IEnumerable 之间的区别,并且我知道 Linq To Objects 通过 IEnumerable 接口(interface)支持集合。

令我困惑的是,当集合转换为 IQueryable 时,查询的执行速度是原来的两倍。

l 成为 类型的填充对象列表 ,那么如果列表 ,则 linq 查询的速度是两倍l 转换为 可查询 通过 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

以下是我的问题:
  • 我究竟做错了什么?
  • 为什么是 IEnumerable 如果在 之后执行测试,则更快可查询 测试?
  • 为什么是 可查询 快的时候没有。试运行次数增加?
  • 使用 是否涉及罚款?可查询 而不是 IEnumerable ?

  • 我问这些问题是因为我想知道将哪一个用于我的存储库接口(interface)。现在他们查询内存中的集合(Linq to Objects),但将来这可能是一个 SQL 数据源。如果我现在用 设计存储库类可查询 以后我可以轻松地切换到 Linq to SQL。但是,如果存在性能损失,则坚持使用 IEnumerable 虽然不涉及 SQL 似乎更明智。

    最佳答案

    使用 linqpad 检查 IL 代码,这就是我所看到的:

    对于此代码:

    var l = Enumerable.Range(0,100);

    var result = from i in l.AsEnumerable() where (i % 10) == 0 && (i % 3) != 0 select i;

    这是生成的:
    IL_0001:  ldc.i4.0    
    IL_0002: ldc.i4.s 64
    IL_0004: call System.Linq.Enumerable.Range
    IL_0009: stloc.0
    IL_000A: ldloc.0
    IL_000B: call System.Linq.Enumerable.AsEnumerable
    IL_0010: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
    IL_0015: brtrue.s IL_002A
    IL_0017: ldnull
    IL_0018: ldftn b__0
    IL_001E: newobj System.Func<System.Int32,System.Boolean>..ctor
    IL_0023: stsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
    IL_0028: br.s IL_002A
    IL_002A: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
    IL_002F: call System.Linq.Enumerable.Where
    IL_0034: stloc.1

    b__0:
    IL_0000: ldarg.0
    IL_0001: ldc.i4.s 0A
    IL_0003: rem
    IL_0004: brtrue.s IL_0011
    IL_0006: ldarg.0
    IL_0007: ldc.i4.3
    IL_0008: rem
    IL_0009: ldc.i4.0
    IL_000A: ceq
    IL_000C: ldc.i4.0
    IL_000D: ceq
    IL_000F: br.s IL_0012
    IL_0011: ldc.i4.0
    IL_0012: stloc.0
    IL_0013: br.s IL_0015
    IL_0015: ldloc.0
    IL_0016: ret

    对于这段代码:
    var l = Enumerable.Range(0,100);

    var result = from i in l.AsQueryable() where (i % 10) == 0 && (i % 3) != 0 select i;

    我们得到这个:
    IL_0001:  ldc.i4.0    
    IL_0002: ldc.i4.s 64
    IL_0004: call System.Linq.Enumerable.Range
    IL_0009: stloc.0
    IL_000A: ldloc.0
    IL_000B: call System.Linq.Queryable.AsQueryable
    IL_0010: ldtoken System.Int32
    IL_0015: call System.Type.GetTypeFromHandle
    IL_001A: ldstr "i"
    IL_001F: call System.Linq.Expressions.Expression.Parameter
    IL_0024: stloc.2
    IL_0025: ldloc.2
    IL_0026: ldc.i4.s 0A
    IL_0028: box System.Int32
    IL_002D: ldtoken System.Int32
    IL_0032: call System.Type.GetTypeFromHandle
    IL_0037: call System.Linq.Expressions.Expression.Constant
    IL_003C: call System.Linq.Expressions.Expression.Modulo
    IL_0041: ldc.i4.0
    IL_0042: box System.Int32
    IL_0047: ldtoken System.Int32
    IL_004C: call System.Type.GetTypeFromHandle
    IL_0051: call System.Linq.Expressions.Expression.Constant
    IL_0056: call System.Linq.Expressions.Expression.Equal
    IL_005B: ldloc.2
    IL_005C: ldc.i4.3
    IL_005D: box System.Int32
    IL_0062: ldtoken System.Int32
    IL_0067: call System.Type.GetTypeFromHandle
    IL_006C: call System.Linq.Expressions.Expression.Constant
    IL_0071: call System.Linq.Expressions.Expression.Modulo
    IL_0076: ldc.i4.0
    IL_0077: box System.Int32
    IL_007C: ldtoken System.Int32
    IL_0081: call System.Type.GetTypeFromHandle
    IL_0086: call System.Linq.Expressions.Expression.Constant
    IL_008B: call System.Linq.Expressions.Expression.NotEqual
    IL_0090: call System.Linq.Expressions.Expression.AndAlso
    IL_0095: ldc.i4.1
    IL_0096: newarr System.Linq.Expressions.ParameterExpression
    IL_009B: stloc.3
    IL_009C: ldloc.3
    IL_009D: ldc.i4.0
    IL_009E: ldloc.2
    IL_009F: stelem.ref
    IL_00A0: ldloc.3
    IL_00A1: call System.Linq.Expressions.Expression.Lambda
    IL_00A6: call System.Linq.Queryable.Where
    IL_00AB: stloc.1

    所以看起来区别是 AsQuerable版本正在构建表达式树, AsEnumerable才不是。

    关于performance - 为什么使用 Linq To Objects 时 IQueryable 比 IEnumerable 快两倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11032966/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com