如果你的搜索是Linq更快的Foreach答案总是不是一个foreach是.我还发现了另一个stackoverflow问题,问题提问者没有做过"热身",所以我在我的代码中加入了"热身".
我的代码示例由于某种原因没有像我预期的那样行事.我在想我做的是让无linq路径循环两次 - 第一次和总和一次.其中linq示例在它结束时仅在结尾处循环一次.你怎么看?我的测试是否存在缺陷,或者这是linq实际上为我们带来了良好的性能提升的情况?
public class NumberObject { public Int32 Number { get; set; } }
public IEnumerable<NumberObject> GetNumbersWithoutLambda()
{
IEnumerable<Int32> numberRange = Enumerable.Range(0,10);
List<NumberObject> numberList = new List<NumberObject>();
foreach (Int32 item in numberRange)
{
numberList.Add(new NumberObject() { Number = item });
}
return numberList;
}
public IEnumerable<NumberObject> GetNumbersWithLambda()
{
IEnumerable<Int32> numberRange = Enumerable.Range(0, 10);
IEnumerable<NumberObject> numbers = numberRange.
Select(number => new NumberObject() { Number = number });
return numbers;
}
private void runGetNumbers(Func<IEnumerable<NumberObject>> getNumbersFunction, Int32 numberOfTimesToRun)
{
for (int i = 0; i < numberOfTimesToRun; i++)
{
IEnumerable<NumberObject> numbers = getNumbersFunction();
//numbers.Count();
numbers.Sum(item => item.Number);
//numbers.Average(item => item.Number);
}
}
[TestMethod]
public void record_speed_of_GetNumbers()
{
Int32 numberOfTimes = 10000000;
Console.WriteLine("Doing warmup... " +
TimeMethod(() => runGetNumbers(GetNumbersWithLambda, numberOfTimes)));
Console.WriteLine("GetNumbersWithoutLambda: " +
TimeMethod(() => runGetNumbers(GetNumbersWithoutLambda, numberOfTimes)) + " milliseconds");
Console.WriteLine("GetNumbersWithLambda: " +
TimeMethod(() => runGetNumbers(GetNumbersWithLambda, numberOfTimes)) + " milliseconds");
}
static long TimeMethod(Action methodToTime)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
methodToTime();
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
Run Code Online (Sandbox Code Playgroud)
以下是测试的输出:
做热身...... 7560
GetNumbersWithoutLambda: 14779毫秒
GetNumbersWithLambda: 7626毫秒
有趣的是,"热身"运行实际上似乎并不适用于这种情况.
Bra*_*NET 11
当LINQ可以利用延迟执行时,它通常会更快; 就像它在这里一样.
如你所料; foreach在代码中完全枚举集合.Select只是构建一个查询来执行该枚举.
然后,当您调用时Sum,它枚举以前生成的集合.我们总共有2个枚举foreach,只有一个Select,所以速度更快(2倍!)
还有其他例子; Take,并将First提前停止执行(foreach 可以提前停止,但大多数人不会这样编码).
基本上,foreach当您实际需要枚举整个集合以进行正在执行的操作时,或者当您想要枚举(使用)LINQ查询时,请使用它.在运行查询和操作时使用LINQ,其中延迟执行将为您带来性能优势.当该查询返回一个集合时,用于foreach迭代它.
你正在比较苹果和橘子,Linq没有像你的"非lambda"版本那样使用List <>.那份清单不是免费的.
你需要像这样写:
public IEnumerable<NumberObject> GetNumbersWithoutLambda() {
IEnumerable<Int32> numberRange = Enumerable.Range(0, 10);
foreach (Int32 item in numberRange) {
yield return new NumberObject() { Number = item };
}
}
Run Code Online (Sandbox Code Playgroud)
现在需要相同的时间.是的,Linq也使用了迭代器.
然而,这并不望其项背的unlinquified版本,它是5快倍:
static int sum; // Ensures summing doesn't get optimized away
private void runGetNumbers2(Int32 numberOfTimesToRun) {
for (int i = 0; i < numberOfTimesToRun; i++) {
foreach (var number in Enumerable.Range(0, 10)) {
sum += number;
}
}
}
Run Code Online (Sandbox Code Playgroud)
让它另一个3更快倍还通过降低Enumerable.Range:
for (int i = 0; i < numberOfTimesToRun; i++) {
for (int j = 0; j < 10; ++j) {
sum += j;
}
}
Run Code Online (Sandbox Code Playgroud)
这表明迭代器使用的状态机也不是免费的.这里的基本前提是简单的代码很快.
不同之处在于,即使List实现了IEnumerable,它也必须在方法返回之前完全填充,Linq方法只需要在返回之前构造表达式树.
考虑并计算以下时间:
public IEnumerable<NumberObject> GetNumbersWithLambdaToList()
{
IEnumerable<Int32> numberRange = Enumerable.Range(0, 10);
IEnumerable<NumberObject> numbers = numberRange.
Select(number => new NumberObject() { Number = number });
return numbers.ToList();
}
public IEnumerable<NumberObject> GetNumbersWithYield()
{
IEnumerable<Int32> numberRange = Enumerable.Range(0,10);
foreach (Int32 item in numberRange)
{
yield return (new NumberObject() { Number = item });
}
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上:
GetNumbersWithoutLambda: 9631 milliseconds
GetNumbersWithLambda: 7285 milliseconds
GetNumbersWithLambdaToList: 12998 milliseconds
GetNumbersWithYield: 9236 milliseconds
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4477 次 |
| 最近记录: |