简体   繁体   English

Linq 在 `Where` 中使用新的 object 查询性能

[英]Linq query performance with new object in `Where`

Is there a performance difference between this:这之间是否存在性能差异:

var listOfFoo = bar.Where(x => x.Id == new Guid("sth")).toList();

and this:和这个:

var guid = new Guid("sth");
var listOfFoo = bar.Where(x => x.Id == guid).toList();

? ?

Probably not when bar is some kind of dynamic set (then query is converted to SQL).bar是某种动态集(然后查询转换为 SQL)时,可能不会。
But if it's a simple enumerable?但如果它是一个简单的可枚举呢?

Yes, there is a real difference: the latter uses a reference to the string instantiated once, but the former calls the lambda which loads the string each time, like any loop where the condition goal part is evaluated every time instead of assigning its value before, when it can be done and when the compiler doesn't know how to optimize itself.是的,有一个真正的区别:后者使用对实例化一次的字符串的引用,但前者调用 lambda 每次加载字符串,就像每次评估条件目标部分而不是之前分配其值的任何循环一样,什么时候可以完成,什么时候编译器不知道如何优化自己。

Calling code:调用代码:

// List<Guid> source2 = source.Where((Guid x) => x == new Guid("sth")).ToList();
IL_000e: ldloc.1
IL_000f: ldsfld class [mscorlib]System.Func`2<valuetype [mscorlib]System.Guid, bool> ConsoleApp.Program/'<>c'::'<>9__29_0'

Compiler lambda factored in an instance method is not optimized:实例方法中的编译器 lambda 未优化:

// return x == new Guid("sth");
IL_0000: ldarg.1
IL_0001: ldstr "sth"
IL_0006: newobj instance void [mscorlib]System.Guid::.ctor(string)
IL_000b: call bool [mscorlib]System.Guid::op_Equality(valuetype [mscorlib]System.Guid, valuetype [mscorlib]System.Guid)
IL_0010: ret

Coder's inlined preallocation: Coder 的内联预分配:

// Guid guid = new Guid("sth");
IL_0046: ldstr "sth"
IL_004b: newobj instance void [mscorlib]System.Guid::.ctor(string)
IL_0050: stfld valuetype [mscorlib]System.Guid ConsoleApp.Program/'<>c__DisplayClass29_0'::guid

// source2 = source.Where((Guid x) => x == guid).ToList();
IL_0055: ldloc.1
IL_0056: ldloc.0
IL_0057: ldftn instance bool ConsoleApp.Program/'<>c__DisplayClass29_0'::'<Test>b__1'(valuetype [mscorlib]System.Guid)

The instance method converted from the lambda is now:从 lambda 转换的实例方法现在是:

// return x == guid;
IL_0000: ldarg.1
IL_0001: ldarg.0
IL_0002: ldfld valuetype [mscorlib]System.Guid ConsoleApp.Program/'<>c__DisplayClass29_0'::guid
IL_0007: call bool [mscorlib]System.Guid::op_Equality(valuetype [mscorlib]System.Guid, valuetype [mscorlib]System.Guid)

Therefore the first requires less string object instances creation, thus less memory and less time, which would obviously only be perceptible on large collections.因此,第一个需要更少的字符串 object 实例创建,因此更少的 memory 和更少的时间,这显然只能在大型 collections 上感知。

It does not matter what the underlying IEnumerable collection and where the elements come from.底层IEnumerable集合是什么以及元素来自何处都没有关系。

But for an IQueryable , the IL code is like writing a query comprehension syntax, and it is optimized for this value to check, regardless of the more complex.但是对于IQueryable ,IL 代码就像编写查询理解语法一样,并且针对该值进行了优化以检查,无论更复杂。

The lambda syntax is not just converted to a comprehension query as if we had used functional-like fluent call chain: lambda 语法不只是转换为理解查询,就好像我们使用了类似函数的流畅调用链:

var query = listOfFoo.AsQueryable().Where(x => x == new Guid("sth")).ToList();

//  List<Guid> list = (from x in source.AsQueryable()
//      where x == new Guid("sth")
//      select x).ToList();
IL_0007: ldloc.0
IL_0008: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::AsQueryable<valuetype [mscorlib]System.Guid>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
// (no C# code)
IL_000d: ldtoken [mscorlib]System.Guid
IL_0012: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0017: ldstr "x"
IL_001c: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
IL_0021: stloc.2
IL_0022: ldloc.2
IL_0023: ldtoken method instance void [mscorlib]System.Guid::.ctor(string)
IL_0028: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_002d: castclass [mscorlib]System.Reflection.ConstructorInfo
IL_0032: ldc.i4.1
IL_0033: newarr [System.Core]System.Linq.Expressions.Expression
IL_0038: dup
IL_0039: ldc.i4.0
IL_003a: ldstr "sth"
IL_003f: ldtoken [mscorlib]System.String
IL_0044: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0049: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
IL_004e: stelem.ref
IL_004f: call class [System.Core]System.Linq.Expressions.NewExpression [System.Core]System.Linq.Expressions.Expression::New(class [mscorlib]System.Reflection.ConstructorInfo, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [System.Core]System.Linq.Expressions.Expression>)
IL_0054: ldc.i4.0
IL_0055: ldtoken method bool [mscorlib]System.Guid::op_Equality(valuetype [mscorlib]System.Guid, valuetype [mscorlib]System.Guid)
IL_005a: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_005f: castclass [mscorlib]System.Reflection.MethodInfo
IL_0064: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression, bool, class [mscorlib]System.Reflection.MethodInfo)
IL_0069: ldc.i4.1
IL_006a: newarr [System.Core]System.Linq.Expressions.ParameterExpression
IL_006f: dup
IL_0070: ldc.i4.0
IL_0071: ldloc.2
IL_0072: stelem.ref
IL_0073: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<valuetype [mscorlib]System.Guid, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
IL_0078: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<valuetype [mscorlib]System.Guid>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
IL_007d: call class [mscorlib]System.Collections.Generic.List`1<!!0> [System.Core]System.Linq.Enumerable::ToList<valuetype [mscorlib]System.Guid>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM