为啥在将 First() 应用于投影时,此 linq 代码会以指数方式变慢?

Posted

技术标签:

【中文标题】为啥在将 First() 应用于投影时,此 linq 代码会以指数方式变慢?【英文标题】:why does this linq code get exponentially slower when applying First() to projection?为什么在将 First() 应用于投影时,此 linq 代码会以指数方式变慢? 【发布时间】:2011-03-01 03:55:59 【问题描述】:

我正在尝试解析一个 500K 的文本文件。

这更像是一种学习练习 - 我知道还有其他方法可以得到我的结果。

我可能会错误地使用 linq-go,因为我对它还是有点陌生​​。

我的电脑很快。

我确定我在这里犯了“经典错误”之一 - 所以我的问题是:它是哪一个,我可以纠正我的逻辑还是这不适合 Linq?

    var lines = File.ReadAllLines(@"C:\Users\aanodide\Desktop\APIUserGuide.txt");
    // add line numbers
    var qa = lines
        .Select((c,i) => new
        
            i = i,
            c = c
        ); 
    var qb = qa.Skip(2312); // defs start at > 2312
    var qc = qb.Where( c => Regex.IsMatch(c.c, @"(\w+): ([a-zA-Z])?(.*)") );
    var qd = qc.Where( c => c.c.StartsWith("API Name:") );
    var qd_desc = qc.Where( c => c.c.StartsWith("Description:") ).Select( d => d.i );
     var qe = qd.Select( c => new 
        i = c.i,
        c = c.c,
        d = qd_desc.First(e => e > c.i) // --> IF I COMMENT OUT THIS, IT RUNS FAST, IN A FRACTION OF A SECOND<--
    ); 
     // Take(1) -> .013s
     // Take(10) -> .070s
     // Take(20) -> .446s
     // Take(40) -> 1.63s
     // Take(80) -> 6.49s
    foreach (var element in qe.Take(50))
    
        Console.WriteLine (element.i);
    

【问题讨论】:

如果我能教大家一件事关于 LINQ,那就是:查询的值是 一个查询。不是查询结果的值!查询的值是查询本身。在您运行查询之前,它不会为您提供结果,并且每次 运行查询时,查询都会运行。如果您不希望查询多次运行请不要多次运行查询 有什么 linq 可以让您绘制执行路径的图表吗?我的直觉是,这样的工具可以帮助我自己解决这个问题。 【参考方案1】:

正如 Mark 所说,当您调用 First() 时,整个查询都会被迭代。并且First()qd 中的每一项都调用一次——这意味着整个文件对qd 中的每一项都解析一次。

要修复它,您可以ToList() qd_desc,然后在该列表中执行First()。那么它只会被评估一次。

var qd_desc = qc.Where( c => c.c.StartsWith("Description:") ).Select( d => d.i ).ToList();

【讨论】:

【参考方案2】:

当您调用First() 时,将执行整个查询(即迭代序列)。当您调用Skip()Where()Select() 或任何返回IEnumerable 的运算符时,查询将不会执行,直到您遍历序列。它发生在First()(或任何返回单个项目的运算符)上的原因是您当时需要一个特定的项目,因此查询必须运行以产生该结果。

【讨论】:

如果我所做的只是用 first 注释掉该行,那么序列的迭代将在几分之一秒内完成...... 正如@saus 指出的那样,您正在为qd 中的每个项目调用First()

以上是关于为啥在将 First() 应用于投影时,此 linq 代码会以指数方式变慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 PhoneGap Android 应用程序在将一堆数据插入 SQL 时崩溃?

为啥在将 Spring Data JPA 与 Spring Boot 结合使用时,我的数据库自定义没有得到应用?

为啥没有自动为 Spring Data REST 项目资源应用摘录投影?

为啥这个 SVG 投影过滤器在路径很短时会剪切路径?

在将约束应用于 UIScrollView 时需要帮助

为啥 SQL Server 在将 int 转换为数据类型 numeric 时抛出算术溢出错误?