LINQ查询速度慢 [英] LINQ query is slow

查看:219
本文介绍了LINQ查询速度慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在应用程序分析我发现功能检查模式匹配是很慢的。它是使用LINQ写入。简单的更换与循环这个LINQ的表达,使真正的巨大差异。它是什么?是LINQ真有这样的坏事和工作如此缓慢或我误解的东西吗?

During application profiling I found that function checking for pattern match is very slow. It is written using LINQ. Simple replacement of this LINQ expression with loop makes really huge difference. What is it? Is LINQ really such a bad thing and works so slow or I misunderstand something?

private static bool PatternMatch1(byte[] buffer, int position, string pattern)
{
    int i = 0;

    foreach (char c in pattern)
    {
        if (buffer[position + i++] != c)
        {
            return false;
        }
    }

    return true;
}    



2版与LINQ(由ReSharper的建议)

version 2 with LINQ (suggested by Resharper)

private static bool PatternMatch2(byte[] buffer, int position, string pattern)
{
    int i = 0;
    return pattern.All(c => buffer[position + i++] == c);
}



3版来与LINQ

version 3 with LINQ

private static bool PatternMatch3(byte[] buffer, int position, string pattern)
{
    return !pattern.Where((t, i) => buffer[position + i] != t).Any();
}



第4版使用lambda

version 4 using lambda

private static bool PatternMatch4(byte[] buffer, int position, string pattern, Func<char, byte, bool> predicate)
{
    int i = 0;

    foreach (char c in pattern)
    {
        if (predicate(c, buffer[position + i++]))
        {
            return false;
        }
    }

    return true;
}

和这里是大缓冲

const int SIZE = 1024 * 1024 * 50;

byte[] buffer = new byte[SIZE];

for (int i = 0; i < SIZE - 3; ++i)
{
    if (PatternMatch1(buffer, i, "xxx"))
    {
        Console.WriteLine(i);
    }
}

调用 PatternMatch2 PatternMatch3 是惊人缓慢。它需要大约8秒 PatternMatch3 约4秒 PatternMatch2 ,同时呼吁 PatternMatch1 约需0.6。据我的理解是相同的代码,我看不出有什么区别。任何想法?

Calling PatternMatch2 or PatternMatch3 is phenomenally slow. It takes about 8 seconds for PatternMatch3 and about 4 seconds for PatternMatch2, while calling PatternMatch1 takes about 0.6. As far as I understand it is the same code and I see no difference. Any ideas?

推荐答案

好吧,让我们Where运算符。

Well let's take the Where operator.

它的实施几乎是(*),如:

It's implementation is almost(*) like:

public IEnumerable<T> Where(this IEnumerable<T> input, Func<T, bool> fn)
{
    foreach(T i in input) 
        if (fn(i))
            yield return i;
}

这意味着,每一个循环结束了IEnumerable创建一个迭代器对象 - 注意。你有SIZE - N这些分配的,因为你做的那些许多LINQ查询

This means, for each loop over the IEnumerable an iterator object is created - note that you have SIZE - n of these allocations because you do those many LINQ queries.

然后为模式中的每个人物有:

Then for each character in the pattern you have:


  1. 系统函数调用来枚举

  2. 函数调用谓词

二是要花费大约一倍一个典型的虚拟呼叫的主叫费用委托的调用(如在第一个版本,你有没有多余的电话分开阵列deindexing。

The second is a call to a delegate which costs roughly double the calling cost of a typical virtual call (where in the first version you have no extra calls apart the array deindexing.

如果你真的想野蛮的表现,你可能想要得到的老式的代码尽可能
在这种情况下,我甚至可以用替换的foreach方法1对于一个普通的(最起码,如果它不服务进行优化,这使得它更具可读性,因为你是跟踪指数的反正)。

If you really want brute performance, you probably want to get as "older-style" code as possible. In this case I would even replace that foreach in method 1 with a plain for (at the very least if it does not serve to optimize, it makes it more readable since you are keeping track of the index anyway).

它也更可读在这种情况下,它表明ReSharper的建议是有时有争议的。

It's also more readable in this case, and it shows that Resharper suggestions are sometimes debatable.

(*)差点所述,因为它使用一个代理方法来检查该输入枚举不空并抛出异常早于集合列举的时间 - 这是一个很小的细节这并不能否定什么,我以前写过,这里强调的完整性。

(*) I said almost because it uses a proxy method to check that the input enumerable is not null and throw the exception earlier than the time the collection is enumerated -- it's a small detail which does not invalidate what I wrote before, highlighting here for completeness.

这篇关于LINQ查询速度慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆