asp.net(c#) foreach和for速度比较
作者:admin 时间:2022-7-4 17:8:28 浏览:asp.net(c#)中foreach和for循环的性能差异表现在它们的速度快慢上,在这篇文章中,我们探讨一下这两者的细微差异。
让我们看一下下面的代码:
foreach (var item in Enumerable.Range(0, 128))
{
Console.WriteLine(item);
}
foreach
在编译器中会被转换为以下代码:
IEnumerator<int> enumerator = Enumerable.Range(0, 128).GetEnumerator();
try
{
while (enumerator.MoveNext())
{
int item = enumerator.Current;
Console.WriteLine(item);
}
}
finally
{
if (enumerator != null)
{
enumerator.Dispose();
}
}
可以看到,foreach
执行的整个过程:
- 创建一个新对象,它被称为Creator。
- 每次迭代都会调用 MoveNext 方法。
- 每次迭代都会访问 Current 属性。
不过,它并不像听起来那么容易。
C#/CLR 可能会在运行时执行优化,使代码运行得更快。
数组是一种深度集成到 CLR 中的类型,CLR 为这种类型提供了许多优化。FOREACH 循环是一个可迭代的实体,这是性能的一个关键方面。在本文后面,我们将讨论如何在 Array.ForEach
静态方法和 List.ForEach
方法的帮助下遍历数组和列表。
测试方法
static double ArrayForWithoutOptimization(int[] array)
{
int sum = 0;
var watch = Stopwatch.StartNew();
for (int i = 0; i < array.Length; i++)
sum += array[i];
watch.Stop();
return watch.Elapsed.TotalMilliseconds;
}
static double ArrayForWithOptimization(int[] array)
{
int length = array.Length;
int sum = 0;
var watch = Stopwatch.StartNew();
for (int i = 0; i < length; i++)
sum += array[i];
watch.Stop();
return watch.Elapsed.TotalMilliseconds;
}
static double ArrayForeach(int[] array)
{
int sum = 0;
var watch = Stopwatch.StartNew();
foreach (var item in array)
sum += item;
watch.Stop();
return watch.Elapsed.TotalMilliseconds;
}
static double ArrayForEach(int[] array)
{
int sum = 0;
var watch = Stopwatch.StartNew();
Array.ForEach(array, i => { sum += i; });
watch.Stop();
return watch.Elapsed.TotalMilliseconds;
}
测试条件:
- “优化代码”选项已打开。
- 元素的数量等于 100 000 000(在数组和列表中)。
- PC 规格:Intel Core i-5 和 8 GB RAM。
数组
该图显示 FOR
和 FOREACH
在遍历数组时花费相同的时间。也是因为CLR优化将FOREACH
转换为FOR
,并以数组的长度作为最大迭代边界。不管数组长度是否缓存(使用FOR
时),结果都差不多。
听起来可能很奇怪,但是缓存数组长度可能会影响性能。在使用Array.Length
作为迭代边界时,JIT 测试索引是否命中循环之外的右边界。此检查仅执行一次。
破坏这种优化非常容易。缓存变量的情况几乎没有优化。
Array.foreach
展示了最差的结果。它的实现非常简单:
public static void ForEach<T>(T[] array, Action<T> action)
{
for (int index = 0; index < array.Length; ++index)
action(array[index]);
}
那为什么它运行这么慢?它在引擎盖下使用 FOR
。原因在于调用 ACTION 委托。事实上,每次迭代都会调用一个方法,这会降低性能。此外,委托的调用速度没有我们希望的那么快。
列表
结果完全不同。迭代列表时,FOR
和 FOREACH
显示不同的结果。没有优化。FOR
(缓存列表长度)显示最佳结果,而 FOREACH
慢 2 倍以上。这是因为它在后台处理 MoveNext
和 Current
。List.ForEach
和 Array.ForEach
显示最差的结果。代表总是被虚拟调用。此方法的实现如下所示:
public void ForEach(Action<T> action)
{
int num = this._version;
for (int index = 0; index < this._size && num == this._version; ++index)
action(this._items[index]);
if (num == this._version)
return;
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
每次迭代都会调用 Action
委托。它还检查列表是否更改,如果更改,则抛出异常。
List
内部使用基于数组的模型,而 ForEach
方法使用数组索引进行迭代,这比使用索引器快得多。
具体数字
- 没有长度缓存的
FOR
循环和FOREACH
在数组上的工作比使用长度缓存的FOR
稍快。 Foreach
性能 比FOR
/FOREACH
性能慢大约 6 倍。- 与数组相比,没有长度缓存的
FOR
循环在列表上的运行速度要慢 3 倍。 - 与数组相比,具有长度缓存的
FOR
循环在列表上的运行速度要慢 2 倍。 - 与数组相比,
FOREACH
循环在列表上的运行速度要慢 6 倍。
这是列表的排行榜:
对于数组:
结论
事实证明,FOREACH
在数组上比 FOR
的长度追踪更快。在列表结构上,FOREACH
比 FOR
慢。
使用 FOREACH
时代码看起来更好,并且现代处理器允许使用它。但是,如果你需要高度优化你的代码库,最好使用 FOR
。
文章推荐
- 站长推荐