在c# / VB.NET/。哪个循环运行得更快,for还是foreach?
自从很久以前我读到for循环比foreach循环工作得快,我就认为它适用于所有集合、泛型集合、所有数组等。
我搜索了谷歌,找到了几篇文章,但大多数都是不确定的(阅读文章评论),而且是开放式的。
理想的情况是列出每种情况以及最佳解决方案。
例如(这只是一个例子):
用于迭代1000+的数组
字符串- for比foreach好
对于迭代IList(非泛型)字符串- foreach更好
比
在网上找到了一些相同的参考资料:
由Emmanuel Schanzer撰写的原创文章
CodeProject FOREACH Vs. FOR
博客——去博客还是不去博客,这是个问题
ASP。NET论坛- NET 1.1 c# for vs foreach
(编辑)
除了可读性之外,我对事实和数据真的很感兴趣。在某些应用中,最后一英里的性能优化确实很重要。
internal static void Test()
{
int LOOP_LENGTH = 10000000;
Random random = new Random((int)DateTime.Now.ToFileTime());
{
Dictionary<int, int> dict = new Dictionary<int, int>();
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
for (int i = 0; i < 64; i++)
{
dict.Add(i, i);
}
for (int i = 0; i < LOOP_LENGTH; i++)
{
for (int k = 0; k < dict.Count; k++)
{
if (dict[k] > 1000000) Console.WriteLine("Test");
}
}
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($"Dictionary for T:{stopWatch.Elapsed.TotalSeconds}s\t M:{last_memory - first_memory}");
GC.Collect();
}
{
Dictionary<int, int> dict = new Dictionary<int, int>();
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
for (int i = 0; i < 64; i++)
{
dict.Add(i, i);
}
for (int i = 0; i < LOOP_LENGTH; i++)
{
foreach (var item in dict)
{
if (item.Value > 1000000) Console.WriteLine("Test");
}
}
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($"Dictionary foreach T:{stopWatch.Elapsed.TotalSeconds}s\t M:{last_memory - first_memory}");
GC.Collect();
}
{
Dictionary<int, int> dict = new Dictionary<int, int>();
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
for (int i = 0; i < 64; i++)
{
dict.Add(i, i);
}
for (int i = 0; i < LOOP_LENGTH; i++)
{
foreach (var item in dict.Values)
{
if (item > 1000000) Console.WriteLine("Test");
}
}
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($"Dictionary foreach values T:{stopWatch.Elapsed.TotalSeconds}s\t M:{last_memory - first_memory}");
GC.Collect();
}
{
List<int> dict = new List<int>();
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
for (int i = 0; i < 64; i++)
{
dict.Add(i);
}
for (int i = 0; i < LOOP_LENGTH; i++)
{
for (int k = 0; k < dict.Count; k++)
{
if (dict[k] > 1000000) Console.WriteLine("Test");
}
}
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($"list for T:{stopWatch.Elapsed.TotalSeconds}s\t M:{last_memory - first_memory}");
GC.Collect();
}
{
List<int> dict = new List<int>();
long first_memory = GC.GetTotalMemory(true);
var stopWatch = Stopwatch.StartNew();
for (int i = 0; i < 64; i++)
{
dict.Add(i);
}
for (int i = 0; i < LOOP_LENGTH; i++)
{
foreach (var item in dict)
{
if (item > 1000000) Console.WriteLine("Test");
}
}
stopWatch.Stop();
var last_memory = GC.GetTotalMemory(true);
Console.WriteLine($"list foreach T:{stopWatch.Elapsed.TotalSeconds}s\t M:{last_memory - first_memory}");
GC.Collect();
}
}
T:10.1957728s M:2080的字典
字典T:10.5900586 M:1952
字典foreach值T:3.8294776s M:2088
T:3.7981471s M:320
T:4.4861377s M:648
每种语言结构都有适当的使用时间和地点。c#语言有四个单独的迭代语句是有原因的——每个语句都有特定的目的,并且有适当的用法。
我建议你和你的老板坐下来,试着理性地解释为什么for循环有一个目的。有时for迭代块比foreach迭代块更清楚地描述算法。在这种情况下,使用它们是合适的。
我还要向你的老板指出——性能不是,也不应该是任何实际方式的问题——这更像是用简洁、有意义、可维护的方式表达算法的问题。这样的微优化完全忽略了性能优化的要点,因为任何真正的性能好处都来自算法重新设计和重构,而不是循环重构。
如果在理性的讨论之后,仍然有这种权威主义的观点,那就取决于你如何继续下去了。就我个人而言,我不会喜欢在一个不鼓励理性思考的环境中工作,我会考虑跳槽到另一个雇主手下。然而,我强烈建议在感到不安之前讨论一下——这可能只是一个简单的误解。