代码之家  ›  专栏  ›  技术社区  ›  sandesh247

LINQ性能-延迟v/s立即执行

  •  3
  • sandesh247  · 技术社区  · 17 年前

    我已经看到,如果使用强制立即执行LINQ to Objects查询,有时可以显著提高查询的性能 .ToArray() Deferred() Immediate() limit 立即()

    public void Deferred()
    {
        var all = Range(limit);
        var even = from e in EvenRange(limit) where all.Contains(e) select e;
        var odd = from o in OddRange(limit) where !even.Contains(o) select o;
    
        var query = from q in odd select q;
    
        foreach(var i in query) { var j = i+1; }
    }
    
    public void Immediate()
    {
        var all = Range(limit);
        var even = (from e in EvenRange(limit) where all.Contains(e) select e)
            .ToArray();
        var odd = (from o in OddRange(limit) where !even.Contains(o) select o)
            .ToArray();
    
        var query = (from q in odd select q).ToArray();
    
        foreach(var i in query) { var j = i+1; }
    }
    
    public static IEnumerable<int> OddRange(int stop)
    {
        for (int i = 1; i < stop; i+=2) yield return i;
    }
    
    public static IEnumerable<int> EvenRange(int stop)
    {
        for (int i = 2; i < stop; i+=2) yield return i;
    }
    
    public static IEnumerable<int> Range(int stop)
    {
        for (int i = 0; i < stop; ++i) yield return i;
    }
    

    延期()

    4 回复  |  直到 17 年前
        1
  •  6
  •   em70    17 年前

        2
  •  2
  •   Guffa    17 年前

    正如emaster70所解释的那样 Deferred even even.Contains limit .

    Immediate all

    var all = Range(limit).ToArray();
    

    它的速度大约快三倍。

    Contains 包含 .

    HashSet 包含

    对于一个 10000,这比 版本:

    public void Joined() {
        var all = Range(limit);
        var even = from e in EvenRange(limit) join a in all on e equals a select e;
        var evenSet = new HashSet<int>(even);
        var odd = from o in OddRange(limit) where !evenSet.Contains(o) select o;
    
        var query = from q in odd select q;
    
        foreach (var i in query) { var j = i + 1; }
    }
    
        3
  •  1
  •   Morten Christiansen    17 年前

        4
  •  1
  •   Brian    17 年前

    在这段代码中

    var all = Range(limit);    
    var even = from e in EvenRange(limit) where all.Contains(e) select e;    
    var odd = from o in OddRange(limit) where !even.Contains(o) select o;
    

    由于由迭代器块或LINQ查询构造的IEnumerous是惰性的,因此计算“奇数”的每个元素都需要重新计算整个“偶数”序列。因此,这段代码的大O非常糟糕。使用一个非常小的“限制”并放置一个控制台可能是有益的。在Range()的循环中写入Line(),并观察其行为。