性能差异c#foreach for linq

时间:2011-04-19 17:09:20

标签: c# .net linq performance foreach

我想知道这是区别:

作为

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中的对象构造新对象(可以与string不同,并且可以包含其他属性......)

我需要表现,所以......

¿什么是最佳选择?为什么?

6 个答案:

答案 0 :(得分:10)

以上都不是。

如果您正在尝试复制数组,我会尝试:

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

arrayOld.CopyTo(arrayNew, 0);

答案 1 :(得分: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

答案 2 :(得分:4)

在大多数情况下,您应该选择最清楚地表达您正在编写的特定代码的意图。然而,如果它是一个非常深的内循环,并且你需要每隔一个纳秒发出吱吱声,我的经验是(使用Release构建代码)一个for循环索引在一个数组上比一个foreach循环快得多,稍微小一点使用带有LINQ的委托与使用循环内部逻辑的简单foreach的性能损失。

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

答案 3 :(得分:3)

至于性能for可能会超过其他人,因为您直接使用索引器,foreach使用Enumerator,因此您需要执行更多行(GetEnumerator, MoveNext,Current等)..但差异是非常微妙并支付代码的可读性可维护性

至于LINQ还有很多工作要做。但想想LINQ为什么要更快?它还在内部使用循环。

大多数情况下,LINQ会慢一点,因为它会引入开销。如果您非常关心性能,请不要使用LINQ。使用LINQ是因为您需要更短的更易读和可维护的代码。


如果您对性能过于敏感并想要在每个最后一个时钟周期生成,那么您可能希望在 unsafe 中使用C样式指针带有fixed变量的上下文

答案 4 :(得分:2)

最快的方式是Array.Copy

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

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

答案 5 :(得分:1)

建立Daniel A. White的评论,不确定它是否严重,但他是对的。你听说过StopWatch课吗?

我认为现在是时候让你花一点时间,学习如何判断自己的表现。如果我们其中一个人真的想要正确回答你的问题,我们就必须编写性能检查代码,这就是为什么你的问题可能会收到这么多的投票。因为你应该这样做。但我们会帮助你:)

您可以使用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的代码片段)