2011-04-19 80 views
1

我想知道这就是区别之间:差异表现C#中的foreach对LINQ

FOR:

string[] arrayOld = new string(){"This", "other", "aaa", ...}; 
string[] arrayNew = new string[arrayOld.lenght]; 

for(int i = i < arrayOld.lenght; i++){ 
    arrayNew[i] = arrayOld[i]; 
} 

FOREACH:

string[] arrayOld = new string(){"This", "other", "aaa", ...}; 
List<string> listNew = new List<string>(); 

foreach(string val in arrayOld){ 
    listNew.add(val); 
} 
string[] arrayNew = listNew.toArray(); 

LINQ:

string[] arrayOld = new string(){"This", "other", "aaa", ...}; 
string[] arrayNew = (from val in arrayOld select val).toArray(); 

我不想复制一个数组...

的想法是在arrayOld构建从对象的新对象(即可以从不同的字符串,可以包含其他属性...)

我需要性能,所以...

¿什么是最好的选择,为什么?

+9

你以前使用'StopWatch'? – 2011-04-19 17:11:01

+10

此代码:'(从arrayOld select val中的val).toArray();'是人们为什么应该熟悉LINQ的非查询式窗体的一个很好的例子。换句话说:'arrayOld.ToArray();' – 2011-04-19 17:13:57

+0

@ChaosPandion - 在OP防御中,他的代码被正确缩进。 StackOverflow中存在一个错误,它不会格式化编号/项目符号列表中的代码。 – 2011-04-19 17:34:05

回答

10

粗结果不言最适合自己:

class Program 
{ 
    static void Main() 
    { 
     // Warm-up 
     Method1(); 
     Method2(); 
     Method3(); 

     const int Count = 1000000; 

     var watch = Stopwatch.StartNew(); 
     for (int i = 0; i < Count; i++) 
     { 
      Method1(); 
     } 
     watch.Stop(); 
     Console.WriteLine("Method1: {0} ms", watch.ElapsedMilliseconds); 

     watch = Stopwatch.StartNew(); 
     for (int i = 0; i < Count; i++) 
     { 
      Method2(); 
     } 
     watch.Stop(); 
     Console.WriteLine("Method2: {0} ms", watch.ElapsedMilliseconds); 

     watch = Stopwatch.StartNew(); 
     for (int i = 0; i < Count; i++) 
     { 
      Method3(); 
     } 
     watch.Stop(); 
     Console.WriteLine("Method3: {0} ms", watch.ElapsedMilliseconds); 

    } 

    static void Method1() 
    { 
     string[] arrayOld = new[] { "This", "other", "aaa" }; 
     string[] arrayNew = new string[arrayOld.Length]; 

     for (var i = 0; i < arrayOld.Length; i++) 
     { 
      arrayNew[i] = arrayOld[i]; 
     } 
    } 

    static void Method2() 
    { 
     string[] arrayOld = new[] { "This", "other", "aaa" }; 
     var listNew = new List<string>(arrayOld.Length); 

     foreach(var val in arrayOld) 
     { 
      listNew.Add(val); 
     } 
     string[] arrayNew = listNew.ToArray();  
    } 

    static void Method3() 
    { 
     string[] arrayOld = new[] { "This", "other", "aaa" }; 
     string[] arrayNew = (from val in arrayOld select val).ToArray();  
    } 
} 

打印我的机器上:

Method1: 72 ms 
Method2: 187 ms 
Method3: 377 ms 
+1

但是,在情况2中,您正在为列表重新分配计时。将案例1更改为也使用列表。 – Blindy 2011-04-19 17:20:07

+0

@Bindy,我已经更新Method2,以便没有列表重新分配。 – 2011-04-19 17:22:56

+0

我发现Method2更快,因为'List '的默认大小是4.我们可能会在.NET运行时的结果中看到一些摇摆。 – ChaosPandion 2011-04-19 17:27:15

3

至于性能for可能超过别人,因为你直接使用索引其中foreach您使用的是Enumerator让你有几个多行来执行(的GetEnumerator,调用MoveNext,电流等)。但区别是非常微妙和支付可读性可维护性的代码。

至于LINQ更多的工作。但想一想为什么LINQ应该更快?它也在内部使用循环。

大多数时候,LINQ会慢一点,因为它会引入开销。如果你关心性能,不要使用LINQ。使用LINQ是因为你想要更短的可读和可维护的代码。


这就是说,如果你对性能过于敏感,并希望生产出每一个最后的时钟周期,那么你可能想用C风格指针unsafe语境与fixed变量

+1

@Bindind - 嗯......这只是错误的。 foreach循环必须经历获取枚举器和枚举集合的麻烦。 for循环很简单。在for循环为你工作的情况下......它会更快。 – 2011-04-19 17:20:27

+0

@Justin Niessner |所以是不是我所说的。对于简单和foreach使用枚举,你可以指出错误,请 – 2011-04-19 17:22:23

+0

@Shekhar,我认为贾斯汀用于不同的回答他的评论(现在删除)。 – 2011-04-19 17:24:33

10

无的以上。

如果你想复制一个数组,我会尝试:

string[] arrayOld = new { "This", "other", "aaa" }; 
string[] arrayNew = new string[arrayOld.Length]; 

arrayOld.CopyTo(arrayNew, 0); 
+0

+1。请注意,通常,针对*特定*任务设计的专用方法将与此类方法的手动执行版本一样快速或更快(因为人们通常会确保智能地实施此类方法)。因此,即使没有运行任何基准测试,我也预测这种方法在与其他列出方法的速度上具有竞争力。它是可读的,所以坚持下去,除非你运行一个分析器并发现它是一个瓶颈。当然,在这种情况下,我会进一步预测你的算法有一个算法缺陷,而不是需要更高效的阵列拷贝例程。 – Brian 2011-04-19 17:51:29

2

最快的方式将Array.Copy

string[] arrayOld = new string[] { "This", "other", "aaa" }; 
string[] arrayNew = new string[arrayOld.Length]; 

Array.Copy(arrayOld, arrayNew, arrayOld.Length); 
+0

Array.CopyTo总是看起来更清晰(我得到你6秒......嘿嘿)。 – 2011-04-19 17:17:37

4

在大多数情况下,你应该选择一个最明确表示意向的特定代码你在写作。然而,如果它是一个非常深的内部循环,并且你需要吱吱嘎吱地响应每一个最后的纳秒,我的经验是(使用Release构建代码)在数组上进行for循环索引的速度比foreach循环快得多,在LINQ中使用委托与使用循环内逻辑的简单foreach相比,性能会有所下降。

这些观察结果基于AI中使用的评分计算算法的微优化工作,其中评分函数被评估很多次。使用分析工具确定了具体的瓶颈和改进程度,如果您处于这种情况,我强烈建议您使用分析工具。瓶颈很少出现在你认为的地方。

1

Daniel A. White的建筑物的评论,不知道它是否严肃,但他是对的。你有没有听说过StopWatch课程?

我想现在是你抽出时间来学习如何判断自我表现的时候了。如果我们其中一个人真的想正确回答你的问题,我们将不得不编写性能检查代码,这就是为什么你的问题可能会收到如此多的反对票。因为你应该这样做。但是,我们将帮助你:)

你可以以确定哪种方法具有最佳性能使用秒表类以及许多其他技术(计数时钟周期/迭代)。

http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx

using System; 
using System.Diagnostics; 
using System.Threading; 
class Program 
{ 
    static void Main(string[] args) 
    { 
     Stopwatch stopWatch = new Stopwatch(); 
     stopWatch.Start(); 
     Thread.Sleep(10000); // put one of your three scenarios here 
     stopWatch.Stop(); 
     // Get the elapsed time as a TimeSpan value. 
     TimeSpan ts = stopWatch.Elapsed; 

     // Format and display the TimeSpan value. 
     string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
      ts.Hours, ts.Minutes, ts.Seconds, 
      ts.Milliseconds/10); 
     Console.WriteLine("RunTime " + elapsedTime); 
    } 
} 

(从MSDN的代码片段)

+0

这是真的,但我要求因为有更好的办法可以做东西......没有更多 – Caipivara 2011-04-19 17:45:33

+0

是的,我也会好奇的,没有担心,有些人真的不是脚踏实地。 – clamchoda 2011-04-19 17:50:07