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

时间:2011-03-01 03:55:59

标签: c# linq performance profiling

我正在尝试解析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);
    }

2 个答案:

答案 0 :(得分:4)

正如Mark所说,当你致电First()时,整个查询都会被重复。 First()中的每个项目都会调用qd一次 - 这意味着qd中的每个项目都会解析整个文件一次。

要解决此问题,您可以ToList() qd_desc,并在该列表上执行First()。然后它只会被评估一次。

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

答案 1 :(得分:3)

当您调用First()时,将执行整个查询(即,迭代序列)。当您致电Skip()Where()Select()或任何返回IEnumerable的运算符时,在迭代序列之前,查询将不会执行。它在First()(或任何返回单个项目的运算符)上发生的原因是您当时要求特定项目,因此要运行查询 以生成该结果