4

我最近发现了 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();
    }
4

6 回答 6

14

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

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

于 2012-05-17T18:08:04.213 回答
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,所以不要用它来做一些简单的字符串格式化(有更好的替代方案)。

于 2012-05-17T18:27:17.367 回答
4

LinQ 非常适合让事情变得简单。就性能而言,如果您开始对列表、数组等进行大量转换,这确实会成为一个问题。

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

这是众所周知的杀手锏,尽量晚点转换成最终名单。

于 2012-05-17T18:14:38.230 回答
2

在大多数情况下,我同意@MarkByers。Linq 的效率将低于过程代码。一般来说,不足之处可以追溯到表达式树的编译。尽管如此,在 99% 的情况下,可读性和时间改进是值得的。当您遇到性能问题时,进行基准测试、修改和重新基准测试。

话虽如此,LINQ 与 lambda 和匿名委托密切相关。这些功能经常被谈论,好像它们是同一个东西。在某些情况下,这些构造可能比过程代码更快。 看起来您的示例可能是其中一种情况。我会重写你的代码如下:

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。在什么场景下哪个速度更快,已经泼了很多墨水。这是一些墨水:

于 2012-05-17T18:28:37.707 回答
1

许多 LINQ 语句很容易并行化。 只需添加AsParallel()到查询的开头。AsOrdered()如果您希望以牺牲一些性能为代价来保留原始订单,您也可以添加。例如,以下 LINQ 语句:

arr.Where(IsAccepted).ToArray();

可以写成:

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

你只需要确保它的开销不会超过它的好处

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
于 2012-05-20T20:27:40.967 回答
1

每个好的书面命令式代码都会比好的书面声明式代码更节省时间和空间,因为必须将声明式代码转换为命令式代码(除非你拥有一台 Prolog 机器......你可能没有,因为你在问。网 :-) )。

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

var actualPrices = allPrices
    .Where(price => price.ValidFrom <= today && price.ValidTo >= today)
    .Select(price => price.PriceInUSD)
    .ToList();

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

一些 LINQ 表达式可以使用 Parallel LINQ 轻松并行化,几乎是“免费”的(= 没有更多代码,但并行开销仍然存在,所以算上它)。

于 2013-06-03T11:09:02.530 回答