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

本文关键字:方法 原始 之间 性能 LINQ 自定义 实现 比较 | 更新日期: 2023-09-27 18:26:23

当我发现一些自定义实现实际上比原始实现运行得更快时,我正忙于实现一些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与原始的执行方式也略有不同,尽管实现方式几乎完全相同,但我现在只对WhereSelect感兴趣

我的问题:

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

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

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

为了获得信息,我将其调整为:

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获胜。

正如另一位用户所指出的,您的测试是有缺陷的,因为除了创建枚举器之外,没有执行任何代码(您没有具体化序列)。但它也有缺陷,还有第二个原因,你肯定要测试很多次,但都是在极其微小的序列上!在更多的元素上尝试同样的测试!

相关文章: