考虑一下:
必要的:
//The alphabet from a-z
List<char> letterRange = Enumerable.Range('a', 'z' - 'a' + 1)
.Select(i => (Char)i).ToList(); //97 - 122 + 1 = 26 letters/iterations
标准foreach:
foreach (var range in letterRange)
{
Console.Write(range + ",");
}
Console.Write("\n");
内置的foreach:
letterRange.ForEach(range => Console.Write(range + ",")); //delegate(char range) works as well
Console.Write("\n");
我已经尝试过将它们相互对准,并且内置的foreach速度提高了2倍,这似乎很多。
我用谷歌搜索过,但我似乎找不到任何答案。
另外,关于:In .NET, which loop runs faster, 'for' or 'foreach'?
for (int i = 0; i < letterRange.Count; i++)
{
Console.Write(letterRange[i] + ",");
}
Console.Write("\n");
据我所知,不会比标准foreach更快地执行。
答案 0 :(得分:17)
我认为你的基准是有缺陷的。 Console.Write
是一个I / O绑定任务,它是您的基准测试中最耗时的部分。这是一个微观基准,应该非常仔细地进行准确的结果。
这是一个基准:http://diditwith.net/PermaLink,guid,506c0888-8c5f-40e5-9d39-a09e2ebf3a55.aspx(看起来不错,但我自己没有验证过)。 自2015年8月14日起,该链接似乎已被破坏
答案 1 :(得分:10)
当您输入foreach循环时,您会枚举每个项目。该枚举导致每次迭代两次方法调用:一次调用IEnumerator<T>.MoveNext()
,另一次调用IEnumerator<T>.Current
。这是两条call
IL指令。
List<T>.ForEach
更快,因为每次迭代只有一个方法调用 - 无论你提供的Action<T>
代理是什么。 这是一条callvirt
IL指令。这明显快于两条call
指令。
正如其他人所指出的那样,像Console.WriteLine()
这样的IO绑定指令会污染你的基准。做一些可以完全局限于记忆的事情,比如一起添加序列的元素。
答案 2 :(得分:2)
这是因为foreach方法没有使用枚举器。枚举器(foreach)往往比基本for循环慢:
以下是ForEach方法的代码:
public void ForEach(Action<T> action)
{
if (action == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
action(this._items[i]);
}
}
虽然我希望会有所不同,但我有点惊讶它和你指出的一样大。使用枚举器方法,您将创建额外的对象,然后采取额外的步骤以确保枚举器不会失效(集合已被修改)。您还需要通过一个额外的函数调用Current()来获取该成员。所有这些都增加了时间。