LINQ 评估被推迟。 primes 和 numbers.Where(n => isOddAndNotDivisibleBy(n)) 的表达式与编译器相同。在这两种情况下,在计算表达式的结果之前,永远不会调用 isOddAndNotDivisibleBy 。在这种情况下,c 和 b 之间的 ToArray 会强制进行计算。如果您在 a 和 b 之间添加 ToArray,您会得到类似的时间。
为了进行比较,您可以尝试:
var primes = (
from n in numbers
where isOddAndNotDivisibleBy(n)
select n).ToArray();
LINQ evaluation is deferred. The expression for primes and numbers.Where(n => isOddAndNotDivisibleBy(n)) are identical to the compiler. In both cases, isOddAndNotDivisibleBy is never called until something evaluates a result of the expression. In this case, the ToArray between c and b forces the evaluation. If you added ToArray between a and b, you'd get similar times.
for comparison you could try:
var primes = (
from n in numbers
where isOddAndNotDivisibleBy(n)
select n).ToArray();
What you call “LINQ”, is actually called LINQ query syntax. And what you cal “anonymous lambda” is actually called LINQ method syntax. The important thing is that the expression:
from n in numbers
where isOddAndNotDivisibleBy(n)
select n
is actually transformed to this before compiling:
numbers.Where(n => isOddAndNotDivisibleBy(n))
This means that if you use the former or the latter directly, you will get the same IL code.
So the difference has to be somewhere else. And it's the ToArray() call. Where() is lazy. That means it does almost nothing, unless you actually iterate over the resulting sequence in one way or another. That means that just calling Where() is going to be nigh instantaneous. But if you call ToArray(), the collection is actually iterated and the results are computed immediately. That's why you see such a huge difference.
EDIT:
To the modified question: why use one syntax over the other? Primarily choose the one that is more readable.
There are some methods and overloads that you can't express using query syntax (First(), Aggregate(), Concat()Zip(), overloads that introduce index, …). But you can use one syntax for one part of the query and another for the rest.
There is also one powerful feature of query syntax that can't be easily expressed using method syntax: transparent identifiers, e.g. when using the let clause.
But there are no performance differences between the two syntaxes, at least when used correctly.
您的测试不一样:您在 b 和 c 之间调用 ToArray(),这将分配(然后重新分配,然后实际执行查询后重新分配)内存。
在 a 和 b 之间,您只需创建一个查询,该查询在执行时将执行计算。调用 ToList()、ToArray() 或通过 foreach 循环迭代查询实际上会强制执行;它应该花费几乎完全相同的时间,因为它将从查询理解语法转换为与第二个测试匹配的一系列扩展方法调用。
最后,切勿使用 DateTime.Now 进行计时;使用秒表。
Your tests aren't the same: You are calling ToArray() between b and c, which will allocate (and then reallocate, and then reallocate) memory after actually executing your query.
Between a and b, you just create a query that, when executed, will perform the calculation. Calling ToList(), ToArray(), or iterating the query via foreach loop will actually force it to be executed; it should take almost excatly the same amount of time, since it will be translated from query comprehension syntax into a series of extension method calls that match your second test.
Finally, never use DateTime.Now for timing; use StopWatch.
Because you didn't execute linq one just do primes .ToArray() and then compare them. in fact this is a deffered execution behavior of linq, it just creates query and didn't run it, til you execute it with some function like, foreach, ToList, ...
Also both of things you done is linq, because both are using some extension methods on IEnumerable in Enumerable class, just first one is query syntax and second one is Dot Notation syntax. see them in msdn linq.
Both of those cases are, indeed, identical LINQ queries, but with different syntactical sugar.
What do I mean by queries? A LINQ query, whether you create it with mySequence.Where(i => i > 5) or (from item in mySequence where item > 5), the only data that is stored is that which allows you to enumerate the sequence.
When you ToArray or ToList or ToDictionary or foreach, the sequence is then evaluated, which is why you have such a huge performance gap -- i.e. your first query is not evaluated. Ever.
发布评论
评论(5)
LINQ 评估被推迟。
primes
和numbers.Where(n => isOddAndNotDivisibleBy(n))
的表达式与编译器相同。在这两种情况下,在计算表达式的结果之前,永远不会调用isOddAndNotDivisibleBy
。在这种情况下,c
和b
之间的ToArray
会强制进行计算。如果您在a
和b
之间添加 ToArray,您会得到类似的时间。为了进行比较,您可以尝试:
LINQ evaluation is deferred. The expression for
primes
andnumbers.Where(n => isOddAndNotDivisibleBy(n))
are identical to the compiler. In both cases,isOddAndNotDivisibleBy
is never called until something evaluates a result of the expression. In this case, theToArray
betweenc
andb
forces the evaluation. If you added ToArray betweena
andb
, you'd get similar times.for comparison you could try:
你所谓的“LINQ”,实际上叫做LINQ查询语法。而所谓的“匿名 lambda”实际上称为 LINQ 方法语法。重要的是,表达式:
在编译之前实际上被转换为:
这意味着如果你直接使用前者或后者,你将得到相同的IL代码。
所以差异一定在其他地方。这是
ToArray()
调用。Where()
是惰性的。这意味着它几乎不执行任何操作,除非您实际上以一种或另一种方式迭代结果序列。这意味着只需调用Where()
就几乎是瞬时的。但如果您调用ToArray()
,则实际上会迭代集合并立即计算结果。这就是为什么你会看到如此巨大的差异。编辑:
修改后的问题:为什么使用一种语法而不是另一种语法?主要选择可读性更强的。
有些方法和重载无法使用查询语法来表达(
First()
、Aggregate()
、Concat()
Zip()
,引入索引的重载,...)。但是您可以对查询的一部分使用一种语法,对其余部分使用另一种语法。查询语法还有一个无法使用方法语法轻松表达的强大功能:透明标识符,例如使用
let
子句时。但这两种语法之间没有性能差异,至少在正确使用时是这样。
What you call “LINQ”, is actually called LINQ query syntax. And what you cal “anonymous lambda” is actually called LINQ method syntax. The important thing is that the expression:
is actually transformed to this before compiling:
This means that if you use the former or the latter directly, you will get the same IL code.
So the difference has to be somewhere else. And it's the
ToArray()
call.Where()
is lazy. That means it does almost nothing, unless you actually iterate over the resulting sequence in one way or another. That means that just callingWhere()
is going to be nigh instantaneous. But if you callToArray()
, the collection is actually iterated and the results are computed immediately. That's why you see such a huge difference.EDIT:
To the modified question: why use one syntax over the other? Primarily choose the one that is more readable.
There are some methods and overloads that you can't express using query syntax (
First()
,Aggregate()
,Concat()
Zip()
, overloads that introduce index, …). But you can use one syntax for one part of the query and another for the rest.There is also one powerful feature of query syntax that can't be easily expressed using method syntax: transparent identifiers, e.g. when using the
let
clause.But there are no performance differences between the two syntaxes, at least when used correctly.
您的测试不一样:您在
b
和c
之间调用ToArray()
,这将分配(然后重新分配,然后实际执行查询后重新分配)内存。在
a
和b
之间,您只需创建一个查询,该查询在执行时将执行计算。调用ToList()
、ToArray()
或通过foreach
循环迭代查询实际上会强制执行;它应该花费几乎完全相同的时间,因为它将从查询理解语法转换为与第二个测试匹配的一系列扩展方法调用。最后,切勿使用
DateTime.Now
进行计时;使用秒表。Your tests aren't the same: You are calling
ToArray()
betweenb
andc
, which will allocate (and then reallocate, and then reallocate) memory after actually executing your query.Between
a
andb
, you just create a query that, when executed, will perform the calculation. CallingToList()
,ToArray()
, or iterating the query viaforeach
loop will actually force it to be executed; it should take almost excatly the same amount of time, since it will be translated from query comprehension syntax into a series of extension method calls that match your second test.Finally, never use
DateTime.Now
for timing; useStopWatch
.因为您没有执行 linq,所以只需执行
primes .ToArray()
然后比较它们。事实上,这是一个延迟执行< /em> linq 的行为,它只是创建查询并没有运行它,直到您使用foreach
、ToList
、 等函数执行它。 ..还您所做的两件事都是 linq,因为两者都在 Enumerable 类中的 IEnumerable 上使用一些扩展方法,第一个是查询语法,第二个是点表示法语法。请在 msdn linq 中查看它们。
Because you didn't execute linq one just do
primes .ToArray()
and then compare them. in fact this is a deffered execution behavior of linq, it just creates query and didn't run it, til you execute it with some function like,foreach
,ToList
, ...Also both of things you done is linq, because both are using some extension methods on IEnumerable in Enumerable class, just first one is query syntax and second one is Dot Notation syntax. see them in msdn linq.
这两种情况实际上都是相同的 LINQ 查询,但具有不同的语法糖。
我所说的查询是什么意思? LINQ 查询,无论是使用
mySequence.Where(i => i > 5)
还是(from item in mySequence where item > 5)
创建,仅存储的数据允许您枚举序列。当您使用
ToArray
或ToList
或ToDictionary
或foreach
时,会对序列进行求值,这就是为什么您有这样的结果巨大的性能差距——即你的第一个查询没有被评估。曾经。Both of those cases are, indeed, identical LINQ queries, but with different syntactical sugar.
What do I mean by queries? A LINQ query, whether you create it with
mySequence.Where(i => i > 5)
or(from item in mySequence where item > 5)
, the only data that is stored is that which allows you to enumerate the sequence.When you
ToArray
orToList
orToDictionary
orforeach
, the sequence is then evaluated, which is why you have such a huge performance gap -- i.e. your first query is not evaluated. Ever.