为什么单一(IEnumerable <t>,谓词<t>)效率低下</t> </t>

时间:2014-05-28 15:26:36

标签: c# .net performance linq base-class-library

来自.Net参考的

代码

    public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    {
      if (source == null)
        throw Error.ArgumentNull("source");
      if (predicate == null)
        throw Error.ArgumentNull("predicate");
      TSource source1 = default (TSource);
      long num = 0L;
      foreach (TSource source2 in source)
      {
        if (predicate(source2))
        {
          source1 = source2;
          checked { ++num; }
        }
      }
      switch (num)
      {
        case 0L:
          throw Error.NoMatch();
        case 1L:
          return source1;
        default:
          throw Error.MoreThanOneMatch();
      }
    }

所以问题是:为什么不在有多个匹配的元素时抛出异常?因此,例如,如果我们有一个大集合,我们可以得到一个很大的性能问题。为什么不在代码中编写简单的if?例如:

public static class LinqTester
{
    public static TSource MySingle<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (predicate == null)
            throw new ArgumentNullException("predicate");
        TSource result = default(TSource);
        int count = 0;
        foreach (TSource value in source)
        {
            if (predicate(value))
            {
                checked { ++count; }
                if (count > 1)
                    throw new Exception("MoreThanOneMatch");
                result = value;
            }
        }
        if (count == 0)
            throw new Exception("NoMatch");
        return result;
    }
}

测试:

    static void Main(string[] args)
    {
        var arr = new byte[100000000];

        var sw = Stopwatch.StartNew();
        try
        {
            Console.WriteLine(arr.Single(i => i == 0));
        }
        catch (Exception)
        {
            sw.Stop();
        }
        finally
        {
            Console.WriteLine(sw.Elapsed);
        }


        var sw2 = Stopwatch.StartNew();
        try
        {
            Console.WriteLine(arr.MySingle(i => i == 0));
        }
        catch (Exception)
        {
            sw2.Stop();
        }
        finally
        {
            Console.WriteLine(sw2.Elapsed);
        }

        Console.WriteLine("Difference = {0}", (double) sw.ElapsedTicks/sw2.ElapsedTicks);

    }

结果:

http://ideone.com/A62JOn

我改写了原版Single,因为mono的另一个实现只慢了3.5倍。

0 个答案:

没有答案