首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >.ToArray()的慢LINQ查询

.ToArray()的慢LINQ查询
EN

Stack Overflow用户
提问于 2013-05-10 19:58:09
回答 3查看 1.8K关注 0票数 5

我正在使用以下查询

代码语言:javascript
复制
foreach (var callDetailsForNode_ReArrange in callDetailsForNodes_ReArrange)
{
    var test = from r1 in dtRowForNode.AsEnumerable()
               join r2 in dtFileRowForNode.AsEnumerable()
               on r1.Field<int>("Lng_Upload_Id") equals r2.Field<int>("Lng_Upload_Id")
               where ((r1.Field<string>("Txt_Called_Number") == callDetailsForNode_ReArrange.caller2.ToString()) || r1.Field<string>("Txt_Calling_Number") == callDetailsForNode_ReArrange.caller2.ToString())
               select r2.Field<string>("Txt_File_Name");

    var d = test.Distinct();
}

到目前为止,这个查询运行得很快。但正如我所说的

代码语言:javascript
复制
string[] str =d.ToArray();
strFileName = string.Join(",", str);

它几乎需要4-5秒才能运行。是什么让它在添加.ToArray()时如此缓慢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-05-10 20:00:25

到目前为止,这个查询在任何时候都可以运行。

到目前为止,除了构建一个表示挂起查询的延迟执行模型之外,它实际上还没有做任何事情。它不会开始迭代,直到你在迭代器上调用MoveNext(),即通过foreach,在你的例子中是通过.ToArray()

所以:这需要时间,因为它是在做工作

考虑一下:

代码语言:javascript
复制
static IEnumerable<int> GetData()
{
    Console.WriteLine("a");
    yield return 0;
    Console.WriteLine("b");
    yield return 1;
    Console.WriteLine("c");
    yield return 2;
    Console.WriteLine("d");
}
static void Main()
{
    Console.WriteLine("start");
    var data = GetData();
    Console.WriteLine("got data");
    foreach (var item in data)
        Console.WriteLine(item);
    Console.WriteLine("end");
}

这将输出以下内容:

代码语言:javascript
复制
start
got data
a
0
b
1
c
2
d
end

请注意,工作并不是一次完成的-它既是延迟的(a出现在got data之后),也是假脱机的(我们没有得到a,...,d0,...2)。

相关:这是Distinct()的大致工作原理,来自评论:

代码语言:javascript
复制
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source) {
    var seen = new HashSet<T>();
    foreach(var item in source) {
        if(seen.Add(item)) yield return item;
    }
}

..。

和一个新的Join操作:

代码语言:javascript
复制
public static string Join(this IEnumerable<string> source, string separator) {
    using(var iter = source.GetEnumerator()) {
        if(!iter.MoveNext()) return "";
        var sb = new StringBuilder(iter.Current);
        while(iter.MoveNext())
            sb.Append(separator).Append(iter.Current);
        return sb.ToString();
    }
}

并使用:

代码语言:javascript
复制
string s = d.Join(",");
票数 15
EN

Stack Overflow用户

发布于 2013-05-10 19:59:43

因为在遍历查询之前,查询不会执行任何操作,而.ToArray()就是这样做的。

要注意的一件事是,一旦开始迭代查询,连接的右侧(在您的示例中为r2 in dtFileRowForNode.AsEnumerable())将被完全枚举,即使只访问结果的第一个元素-但在此之前不会。

所以如果你这样做了:

d.First()

r2 in dtFileRowForNode.AsEnumerable()序列将被完全迭代(并在内存中缓冲),但只会计算r1 in dtRowForNode.AsEnumerable()的第一个元素。

因此,如果join中的一个序列比另一个大得多,那么将大序列放在join的左侧(内存方面)会更有效。连接右侧的整个序列将在内存中进行缓冲。

(我应该指出,这只适用于Linq- to -objects。Linq-to-SQL将在数据库中运行这些查询,因此它处理缓冲。)

票数 12
EN

Stack Overflow用户

发布于 2013-05-10 20:02:10

您需要阅读linq语句的延迟计算。除非您显式地在foreach中调用类似于结果的迭代,调用ToArrayToListSumFirst或计算查询的其他方法之一,否则查询不会完成。

所以是您的查询,而不是ToArray调用,花费了大量的时间来完成。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16481740

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档