当前位置:编程学习 > C#/ASP.NET >>

C#迭代: foreach() ?for() ? 还是指针 ?

测试了一下迭代数组的三种方法,如下:

方法一:每个数组元素只用一次:
using System;

namespace Test
{
    class Program
    {
        static unsafe void Main(string[] args)
        {
            long vTickCount = Environment.TickCount;
            bool[] a = new bool[100000000];
            bool b;
            foreach (bool i in a)
                b = i;
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);
            vTickCount = Environment.TickCount;
            for (int i = 0; i < 100000000; i++)
                b = a[i];
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);
            vTickCount = Environment.TickCount;
            fixed (bool* end = &a[100000000-1])
            {
                bool* i = end - 100000000;
                while (i++ < end)
                    b = *i;
            }
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);
            Console.Read();
        }
    }
}


结果:
1873毫秒
1332毫秒
1312毫秒

可以看出,本轮测试 foreach() 最慢,for() 和指针差不多,指针代码不够直观,且要修改项目属性支持不安全代码。






方法二:每个数组元素重复使用多次:
using System;

namespace Test
{
    class Program
    {
        static unsafe void Main(string[] args)
        {
            long vTickCount = Environment.TickCount;
            bool[] a = new bool[100000000];
            bool b;
            foreach (bool i in a)
                for (int j = 0; j < 20; j++)
                    b = i;
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);
            vTickCount = Environment.TickCount;
            for (int i = 0; i < 100000000; i++)
                for (int j = 0; j < 20; j++)
                    b = a[i];
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);
            vTickCount = Environment.TickCount;
            fixed (bool* end = &a[100000000 - 1])
            {
                bool* i = end - 100000000;
                while (i++ < end)
                    for (int j = 0; j < 20; j++)
                        b = *i;
            }
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);
            Console.Read();
        }
    }
}


结果:
14371毫秒
22172毫秒
13610毫秒

可以看出,本轮测试 for() 最慢,foreach() 和指针差不多,指针还是最快。




总结:
foreach()每次迭代,都牵扯到几次写内存操作,这很耽误时间(后台的),但重复使用单个数组元素时,读取快捷的优势就明显了。适合重复使用每次迭代出的变量。还有个缺点,它对于数组相当于只读的。

for()迭代写内存次数比较少,但读内存比较多,每次要读取i,然后寻址再读取,从这里我们也看出来写一次内存比读一次内存耗费时间多。适合少量使用每次迭代出的变量。个人认为10次以下比foreach()快。而且读写数组比较方便。

指针就不说了,快是快,也不至于为了这几毫秒而使代码变成天书吧。 --------------------编程问答-------------------- bu cuo --------------------编程问答-------------------- 你对调foreach()和for()语句块在程序中的顺序试试。多运行几次,结果也可能不一样。
using System;

namespace Test
{
    class Program
    {
        static unsafe void Main()
        {
            bool[] a = new bool[100000000];
            bool b;
            int vTickCount;

            vTickCount = Environment.TickCount;
            for (int i = 0; i < 100000000; i++)
                b = a[i];
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);

            vTickCount = Environment.TickCount;
            foreach (bool i in a)
                b = i;
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);

            vTickCount = Environment.TickCount;
            fixed (bool* end = &a[100000000-1])
            {
                bool* i = end - 100000000;
                while (i++ < end)
                    b = *i;
            }
            Console.WriteLine("耗时{0}毫秒", Environment.TickCount - vTickCount);
        }
    }
}

耗时391毫秒
耗时370毫秒
耗时401毫秒
--------------------编程问答--------------------
using System;
using System.Windows.Forms;

class Test : Form
{
  TextBox textBox1;

  Test()
  {
    textBox1           = new TextBox();
    textBox1.Parent    = this;
    textBox1.Dock      = DockStyle.Fill;
    textBox1.Multiline = true;
    textBox1.WordWrap  = false;

    Button button1     = new Button();
    button1.Parent     = this;
    button1.Text       = "&Test";
    button1.Dock       = DockStyle.Top;
    button1.Click     += new EventHandler(Button1_Click);
  }

  unsafe void Button1_Click(object sender, EventArgs e)
  {
    (sender as Button).Enabled = false;
    
    bool[] a = new bool[100000000];
    bool b;
    int vTickCount;
    
    vTickCount = Environment.TickCount;
    for (int i = 0; i < 100000000; i++)
      b = a[i];
    textBox1.Text += " for:" + (Environment.TickCount - vTickCount).ToString();
    
    vTickCount = Environment.TickCount;
    foreach (bool i in a)
      b = i;
    textBox1.Text += " foreach:" + (Environment.TickCount - vTickCount).ToString();
    
    vTickCount = Environment.TickCount;
    fixed (bool* end = &a[100000000-1])
    {
      bool* i = end - 100000000;
      while (i++ < end)
        b = *i;
    }
    textBox1.Text += " point:" + (Environment.TickCount - vTickCount).ToString();

    textBox1.Text += Environment.NewLine;
    textBox1.Refresh();
    (sender as Button).Enabled = true;
  }

  static void Main()
  {
    Application.Run(new Test());
  }
}

/*
 for:391 foreach:351 point:440
 for:390 foreach:361 point:520
 for:391 foreach:350 point:391
 for:380 foreach:401 point:441
 for:381 foreach:400 point:431
 for:391 foreach:390 point:431
 for:401 foreach:360 point:431
 for:381 foreach:350 point:441
 for:430 foreach:361 point:441
 for:390 foreach:361 point:471
 for:431 foreach:361 point:430
 for:390 foreach:401 point:380
 for:391 foreach:360 point:471
 for:380 foreach:361 point:531
 for:421 foreach:360 point:431
 for:390 foreach:401 point:431
 for:391 foreach:371 point:430
 for:381 foreach:360 point:441
*/
--------------------编程问答--------------------

 for:390 foreach:361 point:471
 for:431 foreach:361 point:430
 for:390 foreach:401 point:380

注意这几行,结果截然不同,有很大的随机性。 --------------------编程问答-------------------- 我对调了,方法一:每个数组元素只用一次。连续测试多次,还是for比foreach快,我机子是图拉丁+512兆SD133内存,也许内存读写速度各个机器不一样吧,你是DDR内存吗? --------------------编程问答-------------------- 我的机器是 DELL Inspiron 510m 笔记本电脑。
你可以试试我写的 Windows Form 版的程序,多按几次[Test]按钮看看运行结果。
--------------------编程问答-------------------- 我的测试结果:
每元素访问一次:for总是最快,指针稍慢一点点,foreach比for效率低50%
每元素访问20次:foreach最快,指针比foreach效率低15%,for比foreach效率低90%

很奇怪的结果 --------------------编程问答-------------------- 这种测试方法并不准确.

你需要排除AppDomain里面其他线程的时间. 需要排除垃圾收集器的时间.

--------------------编程问答-------------------- 不同意这种测试方法并不准确的说法,你实际测试一下,结果还是比较一致的,只不过各个机器硬件不同,结果也不同。 --------------------编程问答-------------------- ...一致是一回事...准确以否是另外一回事.

你如果装有VS 2005, 可以直接新建测试项目,对你的代码进行测试.

或者CLRProfile, 你会发现这种方法与实际内部情况有很明显区别.  --------------------编程问答-------------------- 另外,,,执着于for循环效率实际意义不大.

真实中,更多考虑的怎么减少循环, 避免将大数据操作放在循环中. --------------------编程问答-------------------- 标记一下 
--------------------编程问答-------------------- 我是初学者,我就是想知道,一旦遇到for和foreach都能做的情况,选择哪个更好。所以发帖讨论,学习一下

你说的调试方法我没用过,你说的调试出来的结果和实际运行结果不一致吗?那我应该相信哪个,如果调试结果总是foreach快,而客户机器上实际运行时总是for快的话,调试结果还可信吗? --------------------编程问答-------------------- 不是调试...是测试.

用专门的性能测试工具.

我说过因为你的代码并没有排除GC和其他线程的影响,并不准确 --------------------编程问答-------------------- up --------------------编程问答-------------------- 楼主可以看看这个(仅供参考):
《Effective C#中文版:改善C#程序的50种方法》条款11:优先采用foreach循环语句 --------------------编程问答-------------------- 谢谢啦,又学到东西了 --------------------编程问答-------------------- 推荐用 shrinerain  的方法看看 CLR 底层的东西如何操作。高级语言总是帮你做了很多事情的,而自己不自知, --------------------编程问答-------------------- 对上述的代码用 ILasm 查看一下源码就知道具体的情况了。

foreach 处理 ArrayList 的时候用到了 try...finally...
for 中没有。

至于说到装箱拆箱的动作,两部分内容都有。

ps:机器有差别代码可能有点不同,大家要看谁的性能好,就看一下ILAsm 的代码就一目了然了。
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,