LINQ在简单操作中的效率

时间:2012-05-17 18:06:27

标签: c# performance linq

我最近发现了LINQ,我发现它非常有趣。目前我有以下功能,我不确定它是否会更高效,毕竟产生相同的输出。

你能否告诉我你对此的看法?

该功能只是以一种非常简单的方式删除标点符号:

private static byte[] FilterText(byte[] arr)
    {
        List<byte> filteredBytes = new List<byte>();
        int j = 0; //index for filteredArray

        for (int i = 0; i < arr.Length; i++)
        {
            if ((arr[i] >= 65 && arr[i] <= 90) || (arr[i] >= 97 && arr[i] <= 122) || arr[i] == 10 || arr[i] == 13 || arr[i] == 32)
            {
                filteredBytes.Insert(j, arr[i]) ;
                j++;
            }
        }

        //return the filtered content of the buffer
        return filteredBytes.ToArray();
    }

LINQ替代方案:

    private static byte [] FilterText2(byte[] arr)
    {
        var x = from a in arr
                where ((a >= 65 && a <= 90) || (a >= 97 && a <= 122) || a == 10 || a == 13 || a == 32)
                select a;

        return x.ToArray();
    }

6 个答案:

答案 0 :(得分:14)

LINQ通常比简单循环和过程代码效率稍低,但差异通常很小,阅读的简洁性和易用性通常使得将简单投影和过滤转换为LINQ值得。

如果性能真的很重要,请测量它并自行决定LINQ代码的性能是否足够。

答案 1 :(得分:4)

LinQ很容易保持简单。性能方面,如果您开始对列表,数组等进行大量转换,它确实会成为一个问题。

MyObject.where(...).ToList().something().ToList().somethingelse.ToList();

众所周知,这是一个杀手,尽可能晚地尝试转换为最终名单。

答案 2 :(得分:4)

螺丝性能,LINQ很棒,因为:

private static bool IsAccepted(byte b)
{
    return (65 <= b && b <= 90) || 
           (97 <= b && b <= 122) || 
           b == 10 || b == 13 || b == 32;
}

arr.Where(IsAccepted).ToArray(); // equivalent to FilterText(arr)

即。你不写怎么做,而只是写什么。此外,它与您提供的其他方法一样快(慢):Where(..)ToArray()中懒惰地进行评估,内部创建一个List并将其转换为Array iirc。

顺便说一句,字符串在C#中是Unicode,所以不要用它来做一些简单的字符串格式化(有更好的选择)。

答案 3 :(得分:2)

在大多数情况下,我同意@MarkByers。 Linq的效率会低于程序代码。通常,缺陷可以追溯到表达树的编译。然而,可读性和在99%的情况下,时间的改进值得一试。当您遇到性能问题,基准测试,修改和重新基准测试时。

话虽如此,LINQ与lambdas和匿名代表密切相关。这些功能经常被讨论,好像它们是同一个东西。有个案这些构造比程序代码更快看起来您的示例可能是其中一种情况。我会按如下方式重写您的代码:

private static byte [] FilterText2(byte[] arr) {

   return arr.Where( a=> (a >= 65 && a <= 90)  || 
                         (a >= 97 && a <= 122) || 
                          a == 10 || a == 13   || a == 32
                  ).ToArray();
}

再次,为YMMV做一些特定情景的基准测试。在很多情况下,大量的墨水溢出更快。这是一些墨水:

答案 4 :(得分:1)

Many LINQ statements are easily parallelizable.只需将AsParallel()添加到查询的开头即可。如果您希望以牺牲某些性能为代价保留原始订单,也可以添加AsOrdered()。例如,以下LINQ语句:

arr.Where(IsAccepted).ToArray();

可以写成:

arr.AsParallel().AsOrdered().Where(IsAccepted).ToArray();

您必须确保its overhead doesn't outweigh its benefits

var queryA = from num in numberList.AsParallel()
             select ExpensiveFunction(num); //good for PLINQ

var queryB = from num in numberList.AsParallel()
             where num % 2 > 0
             select num; //not as good for PLINQ

答案 5 :(得分:1)

每个好的书面命令性代码都会比良好的书面声明性代码更有时间和空间效果,因为声明性代码必须转换为命令式代码(除了你拥有Prolog机器......你可能没有,因为你正在询问.Net :-))。

但是,如果使用LINQ以比使用循环更简单,更易读的方式解决问题,那么它是值得的。当你看到像

这样的东西
var actualPrices = allPrices
    .Where(price => price.ValidFrom <= today && price.ValidTo >= today)
    .Select(price => price.PriceInUSD)
    .ToList();

它是“一条线”,它显而易见的是它在第一眼看到的东西。声明一个新的集合,循环旧的集合,写入if并向新的集合添加内容不是。因此,如果您不想保存每毫秒(这可能不是,因为您使用的是.Net而不是使用嵌入式ASM的C),这是一个胜利。 LINQ是高度优化的 - 有更多的代码库 - 一个用于集合,一个用于XML,一个用于SQL ......,因此它通常不会慢得多。没理由不使用它。

使用Parallel LINQ可以很容易地并行化一些LINQ表达式,几乎“免费”(=没有更多代码,但并行开销仍然存在,所以请用它来计算)。