402

在 C#/VB.NET/.NET 中,哪个循环运行得更快,for或者foreach

自从很久以前我读到循环比循环for运行得更快时,我就认为它适用于所有集合、泛型集合、所有数组等。foreach

我搜索了谷歌并找到了几篇文章,但大多数都没有结论(阅读文章的评论)并且是开放式的。

理想的做法是列出每个场景以及相同的最佳解决方案。

例如(只是应该如何做的一个例子):

  1. 用于迭代 1000 多个字符串的数组 -for优于foreach
  2. 用于迭代IList(非通用)字符串 -foreach优于for

在网上找到了一些相同的参考资料:

  1. Emmanuel Schanzer 的原始大旧文章
  2. CodeProject FOREACH 与。为了
  3. 博客 -foreach做或不做foreach,这是个问题
  4. ASP.NET 论坛 - NET 1.1 C#forforeach

[编辑]

除了它的可读性方面,我对事实和数字真的很感兴趣。在某些应用程序中,最后一英里的性能优化确实很重要。

4

41 回答 41

418

Patrick Smacchia 上个月在博客中谈到了这一点,得出以下结论:

  • List 上的 for 循环比 List 上的 foreach 循环便宜 2 倍多。
  • 在数组上循环比在 List 上循环便宜大约 2 倍。
  • 因此,使用 for 在数组上循环比使用 foreach 在 List 上循环便宜 5 倍(我相信这是我们所有人都在做的事情)。
于 2008-12-13T20:14:50.377 回答
177

首先,对德米特里(现已删除)的回答提出反诉。对于数组,C# 编译器发出的代码与foreach等效for循环的代码基本相同。这就解释了为什么对于这个基准,结果基本相同:

using System;
using System.Diagnostics;
using System.Linq;

class Test
{
    const int Size = 1000000;
    const int Iterations = 10000;

    static void Main()
    {
        double[] data = new double[Size];
        Random rng = new Random();
        for (int i=0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }

        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j=0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop: {0}", sw.ElapsedMilliseconds);
    }
}

结果:

For loop: 16638
Foreach loop: 16529

接下来,验证 Greg 关于集合类型的重要性的观点——将数组更改为List<double>上面的 a,你会得到完全不同的结果。它不仅总体上要慢得多,而且 foreach 比按索引访问要慢得多。话虽如此,我仍然几乎总是更喜欢 foreach 而不是 for 循环,因为它使代码更简单 - 因为可读性几乎总是很重要,而微优化很少。

于 2009-01-23T08:26:50.420 回答
164

foreachforloops 比loops表现出更具体的意图

使用foreach循环向使用您的代码的任何人展示您计划对集合的每个成员执行某些操作,而不管其在集合中的位置如何。它还表明您没有修改原始集合(如果您尝试这样做,则会引发异常)。

的另一个优点foreach是它适用于 any IEnumerable,其中 asfor仅对 有意义IList,其中每个元素实际上都有一个索引。

但是,如果您需要使用元素的索引,那么当然应该允许您使用for循环。但是,如果您不需要使用索引,那么拥有一个索引只会使您的代码变得混乱。

据我所知,没有显着的性能影响。在未来的某个阶段,使用foreach在多核上运行来调整代码可能会更容易,但这不是现在需要担心的事情。

于 2009-12-22T15:08:09.773 回答
53

每当有关于性能的争论时,您只需要编写一个小测试,以便您可以使用定量结果来支持您的案例。

使用 StopWatch 类并重复几百万次,以确保准确性。(如果没有 for 循环,这可能很难):

using System.Diagnostics;
//...
Stopwatch sw = new Stopwatch()
sw.Start()
for(int i = 0; i < 1000000;i ++)
{
    //do whatever it is you need to time
}
sw.Stop();
//print out sw.ElapsedMilliseconds

手指交叉的结果表明差异可以忽略不计,您不妨只做最可维护的代码的任何结果

于 2009-12-22T15:08:32.550 回答
52

它总是很接近。对于数组,有时 for会稍微快一些,但foreach更具表现力,并提供 LINQ 等。通常,坚持使用foreach.

此外,foreach在某些情况下可能会进行优化。例如,一个链表对于索引器来说可能很糟糕,但对于foreach. 实际上,LinkedList<T>出于这个原因,该标准甚至没有提供索引器。

于 2008-12-13T19:56:21.600 回答
37

我的猜测是,在 99% 的情况下它可能并不重要,那么为什么你会选择更快的而不是最合适的(因为最容易理解/维护)?

于 2008-12-13T19:51:41.017 回答
33

有很好的理由更喜欢 foreach循环而不是for循环。如果您可以使用foreach循环,那么您的老板是对的,您应该这样做。

但是,并非每次迭代都只是按顺序逐一遍历列表。如果他是禁止的,是的,那是错误的。

如果我是你,我会做的就是把你所有的自然 for 循环变成 recursion。那会教他,这对你来说也是一个很好的心理锻炼。

于 2009-12-22T15:13:35.243 回答
32

两者之间不太可能存在巨大的性能差异。与往常一样,当面临“哪个更快?”时 问题,您应该始终认为“我可以衡量这个”。

在循环体中写两个做同样事情的循环,执行它们并计时,看看速度上有什么不同。使用几乎为空的主体和类似于您实际执行的循环主体来执行此操作。也可以尝试使用您正在使用的集合类型,因为不同类型的集合可能具有不同的性能特征。

于 2009-01-23T07:36:03.830 回答
18

杰弗里·里希特在 TechEd 2005 上:

“这些年来我开始学习 C# 编译器对我来说基本上是个骗子。” ..“它涉及很多事情。” .. “就像你做一个 foreach 循环一样......” .. “......这是你写的一小行代码,但是 C# 编译器为了做到这一点而吐出的东西是惊人的。它提出了一个try/finally 块在那里,在 finally 块内,它将您的变量转换为 IDisposable 接口,如果转换成功,它会在其上调用 Dispose 方法,在循环内它会在循环内重复调用 Current 属性和 MoveNext 方法,对象是在幕后创建的。很多人使用 foreach 因为它很容易编码,很容易做......” .. “foreach 在性能方面不是很好,

点播网络广播: http ://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US

于 2009-12-03T15:38:08.113 回答
12

这是荒唐的。没有令人信服的理由禁止 for 循环、性能方面或其他方面。

有关性能基准和其他参数,请参阅Jon Skeet 的博客

于 2009-12-22T15:11:28.707 回答
12

你可以阅读Deep .NET - part 1 Iteration

它涵盖了从 .NET 源代码一直到反汇编的结果(没有第一次初始化)。

例如 - 带有 foreach 循环的数组迭代: 在此处输入图像描述

和 - 使用 foreach 循环列出迭代: 在此处输入图像描述

和最终结果: 在此处输入图像描述

在此处输入图像描述

于 2018-09-21T22:29:34.150 回答
11

如果您使用对象集合,foreach则更好,但如果您增加一个数字,for则循环更好。

请注意,在最后一种情况下,您可以执行以下操作:

foreach (int i in Enumerable.Range(1, 10))...

但它肯定不会表现得更好,与for.

于 2009-12-22T15:08:14.127 回答
10

这应该可以节省您:

public IEnumerator<int> For(int start, int end, int step) {
    int n = start;
    while (n <= end) {
        yield n;
        n += step;
    }
}

采用:

foreach (int n in For(1, 200, 4)) {
    Console.WriteLine(n);
}

为了获得更大的胜利,您可以将三个代表作为参数。

于 2009-12-22T18:37:42.397 回答
9

当您循环遍历数组、列表等常见结构时,afor和 a循环的速度差异很小,并且对集合进行查询几乎总是稍微慢一些,尽管写起来更好!正如其他海报所说,追求表现力而不是一毫秒的额外性能。foreachLINQ

到目前为止还没有说的是,当一个foreach循环被编译时,它会由编译器根据它正在迭代的集合进行优化。这意味着当您不确定要使用哪个循环时,您应该使用foreach循环 - 它会在编译时为您生成最佳循环。它也更具可读性。

循环的另一个关键优势foreach是,如果您的集合实现发生变化(例如从 intarray到 a List<int>),那么您的foreach循环将不需要任何代码更改:

foreach (int i in myCollection)

无论您的集合是什么类型,上述内容都是相同的,而在您的循环中,如果您从 an更改为 a for,则不会构建以下内容:myCollectionarrayList

for (int i = 0; i < myCollection.Length, i++)
于 2008-12-13T20:38:14.760 回答
9

这与大多数“哪个更快”问题具有相同的两个答案:

1)如果你不测量,你就不知道。

2)(因为......)这取决于。

对于您将要迭代的 IEnumerable 类型(或多个类型),这取决于“MoveNext()”方法相对于“this[int index]”方法的成本有多高。

“foreach”关键字是一系列操作的简写——它在 IEnumerable 上调用一次 GetEnumerator(),每次迭代调用一次 MoveNext(),进行一些类型检查,等等。最有可能影响性能测量的是 MoveNext() 的成本,因为它被调用了 O(N) 次。也许它很便宜,但也许不是。

“for”关键字看起来更容易预测,但在大多数“for”循环中,您会发现类似“collection[index]”的内容。这看起来像一个简单的数组索引操作,但它实际上是一个方法调用,其成本完全取决于您正在迭代的集合的性质。也许它很便宜,但也许不是。

如果集合的底层结构本质上是一个链表,则 MoveNext 非常便宜,但索引器可能有 O(N) 成本,使得“for”循环的真正成本为 O(N*N)。

于 2014-11-13T06:22:22.247 回答
8

“有什么论据可以用来帮助我说服他使用 for 循环是可以接受的吗?”

不,如果你的老板是微观管理到告诉你使用什么编程语言结构的程度,你真的无话可说。对不起。

于 2009-12-22T15:50:52.980 回答
7

这可能取决于您要枚举的集合类型及其索引器的实现。但总的来说,使用foreach可能是一种更好的方法。

此外,它适用于任何IEnumerable东西——不仅仅是索引器。

于 2009-01-23T07:35:12.617 回答
7

每种语言结构都有适当的使用时间和地点。C# 语言有四个独立的迭代语句是有原因的——每个语句都有特定的用途,并且有适当的用途。

我建议和你的老板坐下来,试着理性地解释为什么for循环有目的。有时for迭代块比迭代更清楚地描述算法foreach。当这是真的时,使用它们是合适的。

我还要向你的老板指出——性能不是,也不应该成为任何实际的问题——它更多的是以简洁、有意义、可维护的方式表达算法的问题。像这样的微优化完全忽略了性能优化的重点,因为任何真正的性能优势都来自算法重新设计和重构,而不是循环重构。

如果经过理性的讨论,还是有这种专制的观点,那怎么做就看你自己了。就个人而言,我不会乐于在不鼓励理性思考的环境中工作,并会考虑跳槽到不同雇主的另一个职位。但是,我强烈建议在生气之前进行讨论——这可能只是一个简单的误解。

于 2009-12-22T18:11:14.850 回答
6

题外话是否forforeach真的快。我严重怀疑选择一个而不是另一个会对你的表现产生重大影响。

优化应用程序的最佳方法是通过分析实际代码。这将查明占工作/时间最多的方法。先优化那些。如果性能仍然不可接受,请重复该过程。

作为一般规则,我建议远离微优化,因为它们很少会产生任何重大收益。唯一的例外是在优化已识别的热路径时(即,如果您的分析识别了一些高度使用的方法,那么对这些方法进行广泛优化可能是有意义的)。

于 2009-12-22T15:31:32.273 回答
5

影响性能的是您循环中所做的事情,而不是实际的循环构造(假设您的情况不重要)。

于 2009-12-22T16:13:47.253 回答
4

两者将以几乎完全相同的方式运行。编写一些代码来使用两者,然后向他展示 IL。它应该显示可比较的计算,这意味着性能没有差异。

于 2009-12-22T15:08:28.747 回答
4

完全禁止使用 for 循环之类的东西似乎有点奇怪。

这里有一篇有趣的文章,涵盖了两个循环之间的许多性能差异。

我个人会说,我发现 foreach 比 for 循环更具可读性,但是如果 for 循环更合适,您应该使用最好的方法来完成手头的工作,而不必编写额外的长代码来包含 foreach 循环。

于 2009-12-22T15:12:25.010 回答
4

在大多数情况下,真的没有什么区别。

通常,当您没有明确的数字索引时,您总是必须使用 foreach,并且当您实际上没有可迭代的集合时(例如,在上三角形中迭代二维数组网格)时,您总是必须使用 for . 在某些情况下,您可以选择。

有人可能会争辩说,如果代码中开始出现幻数,那么 for 循环可能会更难以维护。你应该为不能使用 for 循环而感到恼火,而不得不构建一个集合或使用 lambda 来构建一个子集合,而不是仅仅因为 for 循环已被禁止。

于 2009-12-22T15:12:51.997 回答
4

你真的可以把他的脑袋搞砸,改为使用 IQueryable .foreach 闭包:

myList.ForEach(c => Console.WriteLine(c.ToString());
于 2009-12-22T15:45:01.477 回答
3

前段时间我确实测试过它,结果for循环比循环快得多foreach。原因很简单,foreach循环首先需要IEnumerator为集合实例化一个。

于 2008-12-13T19:57:33.780 回答
3

for 具有更简单的实现逻辑,因此它比 foreach 更快。

于 2008-12-13T19:59:32.233 回答
3

除非您处于特定的速度优化过程中,否则我会说使用产生最容易阅读和维护代码的任何方法。

如果已经设置了迭代器,例如其中一个集合类,那么 foreach 是一个很好的简单选择。如果它是您正在迭代的整数范围,那么 for 可能更干净。

于 2009-01-23T09:02:19.100 回答
3

Jeffrey Richter 在最近的播客中谈到了 for 和 foreach 之间的性能差异:http ://pixel8.infragistics.com/shows/everything.aspx#Episode:9317

于 2009-01-23T10:16:38.500 回答
3

我找到了迭代更快foreach的循环。请参阅下面的测试结果。在下面的代码中,我分别使用和循环来迭代大小为 100、10000 和 100000的值来测量时间。List arrayforforeach

在此处输入图像描述

private static void MeasureTime()
    {
        var array = new int[10000];
        var list = array.ToList();
        Console.WriteLine("Array size: {0}", array.Length);

        Console.WriteLine("Array For loop ......");
        var stopWatch = Stopwatch.StartNew();
        for (int i = 0; i < array.Length; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("Array Foreach loop ......");
        var stopWatch1 = Stopwatch.StartNew();
        foreach (var item in array)
        {
            Thread.Sleep(1);
        }
        stopWatch1.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch1.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List For loop ......");
        var stopWatch2 = Stopwatch.StartNew();
        for (int i = 0; i < list.Count; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch2.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch2.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List Foreach loop ......");
        var stopWatch3 = Stopwatch.StartNew();
        foreach (var item in list)
        {
            Thread.Sleep(1);
        }
        stopWatch3.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch3.ElapsedMilliseconds);
    }

更新

在@jgauffin 建议后,我使用了@johnskeet 代码,发现for循环array比跟随要快,

  • 带数组的 Foreach 循环。
  • 带列表的 for 循环。
  • 带有列表的 Foreach 循环。

请参阅下面的测试结果和代码,

在此处输入图像描述

private static void MeasureNewTime()
    {
        var data = new double[Size];
        var rng = new Random();
        for (int i = 0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }
        Console.WriteLine("Lenght of array: {0}", data.Length);
        Console.WriteLine("No. of iteration: {0}", Iterations);
        Console.WriteLine(" ");
        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with Array: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (var i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with Array: {0}", sw.ElapsedMilliseconds);
        Console.WriteLine(" ");

        var dataList = data.ToList();
        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < dataList.Count; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with List: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in dataList)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with List: {0}", sw.ElapsedMilliseconds);
    }
于 2014-06-12T05:34:29.447 回答
2

我不希望任何人发现两者之间的“巨大”性能差异。

我想答案取决于您尝试访问的集合是否具有更快的索引器访问实现或更快的 IEnumerator 访问实现。由于 IEnumerator 经常使用索引器并且只保存当前索引位置的副本,我希望枚举器访问至少与直接索引访问一样慢或更慢,但不会慢很多。

当然,这个答案没有考虑编译器可能实现的任何优化。

于 2009-01-23T10:17:18.403 回答
2

请记住,for 循环和 foreach 循环并不总是等价的。如果列表发生更改,列表枚举器将引发异常,但您不会总是通过正常的 for 循环获得该警告。如果列表在错误的时间更改,您甚至可能会遇到不同的异常。

于 2009-02-17T16:59:48.163 回答
2

我遇到了一个案例,其中 foreach 方式比 For 快

为什么在读取richtextbox行时foreach比for循环快

在那个问题中,我有一个类似于 OP 的案例。

一个读取大约 72K 行的文本框,我正在访问 Lines 属性(这实际上是一个 getter 方法)。(显然,在winforms中经常有不是O(1)的getter方法。我想它是O(n),所以文本框越大,从该“属性”获取值所需的时间就越长。在for循环我和那里的 OP 一样for(int i=0;i<textBox1.lines.length;i++) str=textBox1.Lines[i] ,它真的很慢,因为它每次读取一行时都在读取整个文本框,而且每次检查条件时它都在读取整个文本框。

Jon Skeet 表明您可以只访问一次 Lines 属性(每次迭代甚至一次,仅一次)。而不是每次迭代两次(这是很多次)。做 string[] strarrlines = textBox1.Lines; 并循环通过strarrlines。

但可以肯定的是,以相当直观的形式使用 for 循环并访问 Lines 属性是非常低效的

for (int i = 0; i < richTextBox.Lines.Length; i++)
{
    s = richTextBox.Lines[i];
}

对于文本框或富文本框,它非常慢。

OP 在富文本框上测试该循环,发现“有 15000 行。for 循环需要 8 分钟才能循环到 15000 行。而 foreach 花了几分之一秒来枚举它。”

该链接上的 OP 发现这个 foreach 比上面提到的他的(相同的 OP)for 循环效率更高。正如我所做的那样。

   String s=String.Empty;
   foreach(string str in txtText.Lines)
    {
       s=str;
    }
于 2016-09-23T06:00:27.580 回答
1

我认为在大多数情况下 for 比 foreach 稍微快一点,但这确实没有抓住重点。我没有看到提到的一件事是,在您正在谈论的场景中(即,大容量网络应用程序),for 和 foreach 之间的性能差异将不会影响网站的性能。您将受到请求/响应时间和数据库时间的限制,而不是 v. foreach。

也就是说,我不明白你对 foreach 的厌恶。在我看来,在可以使用任何一种的情况下,foreach 通常会更清晰。我通常保留用于需要以某种丑陋、非标准方式遍历集合的情况。

于 2009-12-22T15:58:18.600 回答
1

在我的 Windows Mobile 项目中,我for为控件集合使用了循环。20 个控件花费了 100 毫秒!一个foreach循环只用了 4 毫秒。那是性能问题...

于 2011-08-10T00:19:56.513 回答
1

Ben Watson,《编写高性能 .NET 代码》的作者:

“这些优化对你的程序很重要吗?只有当你的程序受 CPU 限制并且集合迭代是你处理的核心部分时。正如你将看到的,如果你不小心,有一些方法可能会损害你的性能,但那仅当它是您程序的重要组成部分时才重要。我的理念是:大多数人永远不需要知道这一点,但如果您这样做,那么了解系统的每一层都很重要,这样您就可以做出明智的选择“ .

最详尽的解释可以在这里找到:http: //www.codeproject.com/Articles/844781/Digging-Into-NET-Loop-Performance-Bounds-checking

于 2015-11-08T20:37:48.030 回答
1

我根据 for 和 foreach 的收集速度提到了这个细节。

List -For 循环比 Foreach 循环稍快

ArrayList - For 循环的速度比 Foreach 循环快 2 倍以上。

数组 - 两者的速度相同。但 Foreach 循环似乎要快一些。

于 2016-01-11T04:46:32.080 回答
0

我建议阅读本文以获得具体答案。文章的结论是,使用for循环通常比foreach循环更好更快。

于 2009-01-23T08:45:57.200 回答
0

for至少我没有看到我的任何同事或上级这么说,考虑到和之间没有显着的速度差异这一事实,这简直是荒谬的foreach。如果他要求在所有情况下都使用它,这同样适用!

于 2009-12-22T15:11:53.467 回答
0

从 .NET Framework 4 开始,您还可以使用 Parallel.For 和 Parallel.ForEach,如下所述:C# Multithreading Loop with Parallel.For or Parallel.ForEach

于 2013-12-18T09:39:24.940 回答
0

我需要使用三个嵌套循环(on List<MyCustomType>)来解析一些大数据。我认为,使用上面的 Rob Fonseca-Ensor 的帖子,使用forforeach计时和比较差异会很有趣。

不同之处在于:foreach(嵌套的三个 foreach 像 foreach{foreach{forech{}}} 在171.441秒内完成了这项工作,而 for (for{for{for{}}}) 在158.616秒内完成了这项工作。

现在 13 秒大约减少了13%的时间 - 这对我来说有点重要。但是,foreach 绝对比使用三个索引的 fors 更具可读性......

于 2014-06-27T15:04:55.190 回答
0
    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
字典 foreach T:10.5900586s M:1952
字典 foreach 值 T:3.8294776s M:2088
T:3.7981471s M:320
列表 foreach T:4.4861377s M:648

于 2021-02-24T11:05:34.053 回答