比较自定义实现的LINQ方法和原始方法之间的性能

时间:2014-10-13 12:05:26

标签: c# performance linq

当我发现某些自定义实现实际上比原始实现运行得更快时,我只是在实现一些LINQ方法时,即使实现类似。处理列表而不是数组,使得速度的差异甚至更大于自定义方法的一面!

public static class CustomLINQ
{
    public static IEnumerable<T> WHERE<T>(this IEnumerable<T> items, Func<T, bool> predicate)
    {
        foreach (var item in items)
            if (predicate(item))
                yield return item;
    }

    public static IEnumerable<TReturn> SELECT<TSource, TReturn>(this IEnumerable<TSource> items, Func<TSource, TReturn> projection)
    {
        foreach (var item in items)
            yield return projection(item);
    }
}

public class Program
{
    static int loops  = 1000000;
    static int nTests = 100;

    static void Measure(string msg, Action code)
    {
        long total = 0;
        for (int i = 0; i < nTests; i++)
        {
            var w = Stopwatch.StartNew();
            for (int j = 0; j < loops; j++)
                code();
            total += w.ElapsedMilliseconds;
        }
        Console.WriteLine("(avg) {0} \t {1}ms", msg, total / nTests);
    }

    private static void Main(string[] args)
    {
        var sample = new List<string> { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight" };
        //var sample = new[] { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight" };

        Measure("Linq Where", () =>    { var res = sample.Where(x => true && x.Length % 2 == 0); });
        Measure("Custom Where", () =>  { var res = sample.WHERE(x => true && x.Length % 2 == 0); });
        Measure("Linq Select", () =>   { var res = sample.Select(x => x.Length);                 });
        Measure("Custom Select", () => { var res = sample.SELECT(x => x.Length);                 });

    }
}

示例时间:

(使用清单)

(avg) Linq Where         102ms
(avg) Custom Where       62ms
(avg) Linq Select        122ms
(avg) Custom Select      59ms

(使用数组)

(avg) Linq Where         75ms
(avg) Custom Where       60ms
(avg) Linq Select        77ms
(avg) Custom Select      60ms

自定义AnyAll以及原件的执行情况稍有不同,尽管实施情况几乎完全相同,我只对Where和{{{{}}感兴趣1}}现在

我的问题:

  • 这让我有点怀疑我衡量这一点的方式,我做得对吗?它有什么问题吗?
  • 为什么这个简单的实现似乎比原件更好? (几乎是列表的两倍,而阵列的速度稍快)
  • 在处理列表时,为什么自定义实现和LINQ之间的性能差异大于处理数组时的性能差异?

2 个答案:

答案 0 :(得分:6)

您实际上并没有迭代序列。您正在测试的是枚举器创建性能;不是实际的循环。基本上,测试毫无意义。

有关信息,我将其调整为:

Measure("Linq Where", () => { sample.Where(x => true && x.Length % 2 == 0).Consume(); });
Measure("Custom Where", () => { sample.WHERE(x => true && x.Length % 2 == 0).Consume(); });
Measure("Linq Select", () => { sample.Select(x => x.Length).Consume(); });
Measure("Custom Select", () => { sample.SELECT(x => x.Length).Consume(); });

使用:

public static void Consume<T>(this IEnumerable<T> source)
{
    using(var iter = source.GetEnumerator())
    {
        while (iter.MoveNext()) { }
    }
}

(只是手动烧掉迭代器),将loops更改为500000,然后重试(释放模式,控制台等):

(avg) Linq Where         139ms
(avg) Custom Where       174ms
(avg) Linq Select        132ms
(avg) Custom Select      174ms

LINQ获胜。

答案 1 :(得分:1)

正如另一个人所指出的,你的测试是有缺陷的,因为除了枚举器创建之外没有执行任何代码(你没有实现序列)。但它也有缺陷的第二个原因,你测试的次数肯定很多,但是在极小的序列上!在更多元素上尝试相同的测试!