Итераторы
От: StatujaLeha на правах ИМХО
Дата: 16.06.20 06:49
Оценка: 63 (1)
Приветствую!

Хотел использовать в проекте расширение EnumerableExtensions.Concat<T>(this IEnumerable<T> source, T element).
Посмотрел реализацию: появилось подозрение, что они делают обход коллекции неэффективно.

Набросал свою реализацию.
Код и результаты ниже.
    [SimpleJob(RuntimeMoniker.Net472)]
    [SimpleJob(RuntimeMoniker.NetCoreApp22)]
    public class ConcatBenchmark
    {
        private const int N = 3000000;
        public int[] startInt = Enumerable.Repeat(1, N).ToArray();
        public long[] startLong = Enumerable.Repeat(1l, N).ToArray();
        public string[] startStr = Enumerable.Repeat(1, N).Select(i => i.ToString()).ToArray();

        [Benchmark]
        public int ReferenceCodeJam() => this.startStr.Concat("").Count();

        [Benchmark]
        public int ReferenceMy() => Concat(this.startStr, "").Count();

        [Benchmark]
        public int Referencex5CodeJam() => this.startStr.Concat("").Concat("").Concat("").Concat("").Concat("").Count();

        [Benchmark]
        public int Referencex5My() => Concat(Concat(Concat(Concat(Concat(this.startStr, ""), ""), ""), ""), "").Count();
        
        
        [Benchmark]
        public int intCodeJam() => this.startInt.Concat(N).Sum();

        [Benchmark]
        public int intMy() => Concat(this.startInt, N).Sum();

        [Benchmark]
        public int intx5CodeJam() => this.startInt.Concat(N).Concat(N).Concat(N).Concat(N).Concat(N).Sum();

        [Benchmark]
        public int intx5My() => Concat(Concat(Concat(Concat(Concat(this.startInt, N), N), N), N), N).Sum();


        [Benchmark]
        public long longCodeJam() => this.startLong.Concat(N).Sum();

        [Benchmark]
        public long longMy() => Concat(this.startLong, N).Sum();

        [Benchmark]
        public long longx5CodeJam() => this.startLong.Concat(N).Concat(N).Concat(N).Concat(N).Concat(N).Sum();

        [Benchmark]
        public long longx5My() => Concat(Concat(Concat(Concat(Concat(this.startLong, N), N), N), N), N).Sum();


        public class ConcatEnumerator<T> : IEnumerator<T>
        {
            private State state;

            private IEnumerator<T> start;

            private readonly T last;

            public ConcatEnumerator(IEnumerator<T> start, T last)
            {
                this.state = State.ConsumingFirst;
                this.start = start;
                this.last = last;
            }

            public void Dispose()
            {
            }

            public Boolean MoveNext()
            {
                switch (this.state)
                {
                    case State.ConsumingFirst:
                        if (this.start.MoveNext())
                        {
                            return true;
                        }
                        else
                        {
                            this.state = State.StartConsumed;
                            return true;
                        }

                    case State.StartConsumed:
                        this.state = State.Empty;
                        return false;
                }

                return false;
            }

            public void Reset()
            {
                this.start.Reset();
                this.state = State.ConsumingFirst;
            }

            public T Current
            {
                get
                {
                    switch (this.state)
                    {
                        case State.ConsumingFirst:
                            return this.start.Current;

                        case State.StartConsumed:
                            return this.last;

                        default:
                            throw new InvalidOperationException();
                    }
                }
            }

            Object IEnumerator.Current => this.Current;

            enum State
            {
                ConsumingFirst,

                StartConsumed,

                Empty
            }
        }

        public class ConcatEnumerable<T> : IEnumerable<T>
        {
            private IEnumerable<T> start;

            private readonly T last;

            public ConcatEnumerable(IEnumerable<T> start, T last)
            {
                this.start = start;
                this.last = last;
            }

            public IEnumerator<T> GetEnumerator()
            {
                return new ConcatEnumerator<T>(this.start.GetEnumerator(), this.last);
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }
        }

        public static IEnumerable<T> Concat<T>(IEnumerable<T> first, T last)
        {
            return new ConcatEnumerable<T>(first, last);
        }
    }


BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18363.836 (1909/November2018Update/19H2)
Intel Core i7-10710U CPU 1.10GHz, 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=2.2.106
  [Host]        : .NET Core 2.2.4 (CoreCLR 4.6.27521.02, CoreFX 4.6.27521.01), X64 RyuJIT
  .NET 4.7.2    : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
  .NET Core 2.2 : .NET Core 2.2.4 (CoreCLR 4.6.27521.02, CoreFX 4.6.27521.01), X64 RyuJIT


|             Method |           Job |       Runtime |      Mean |    Error |   StdDev |    Median |
|------------------- |-------------- |-------------- |----------:|---------:|---------:|----------:|
|   ReferenceCodeJam |    .NET 4.7.2 |    .NET 4.7.2 |  34.36 ms | 1.132 ms | 3.247 ms |  33.16 ms |
|        ReferenceMy |    .NET 4.7.2 |    .NET 4.7.2 |  15.28 ms | 0.359 ms | 1.037 ms |  14.76 ms |
| Referencex5CodeJam |    .NET 4.7.2 |    .NET 4.7.2 | 157.93 ms | 0.961 ms | 0.852 ms | 157.82 ms |
|      Referencex5My |    .NET 4.7.2 |    .NET 4.7.2 |  53.54 ms | 1.066 ms | 1.923 ms |  52.89 ms |
|         intCodeJam |    .NET 4.7.2 |    .NET 4.7.2 |  33.20 ms | 0.633 ms | 0.561 ms |  33.07 ms |
|              intMy |    .NET 4.7.2 |    .NET 4.7.2 |  26.45 ms | 0.251 ms | 0.209 ms |  26.42 ms |
|       intx5CodeJam |    .NET 4.7.2 |    .NET 4.7.2 | 119.49 ms | 2.170 ms | 1.695 ms | 119.04 ms |
|            intx5My |    .NET 4.7.2 |    .NET 4.7.2 |  87.00 ms | 1.227 ms | 1.148 ms |  86.95 ms |
|        longCodeJam |    .NET 4.7.2 |    .NET 4.7.2 |  32.32 ms | 0.283 ms | 0.251 ms |  32.30 ms |
|             longMy |    .NET 4.7.2 |    .NET 4.7.2 |  28.16 ms | 0.202 ms | 0.189 ms |  28.10 ms |
|      longx5CodeJam |    .NET 4.7.2 |    .NET 4.7.2 | 118.99 ms | 1.045 ms | 0.978 ms | 118.84 ms |
|           longx5My |    .NET 4.7.2 |    .NET 4.7.2 |  89.98 ms | 1.082 ms | 0.904 ms |  90.05 ms |
|   ReferenceCodeJam | .NET Core 2.2 | .NET Core 2.2 |  32.73 ms | 0.438 ms | 0.388 ms |  32.81 ms |
|        ReferenceMy | .NET Core 2.2 | .NET Core 2.2 |  15.08 ms | 0.098 ms | 0.092 ms |  15.05 ms |
| Referencex5CodeJam | .NET Core 2.2 | .NET Core 2.2 | 166.51 ms | 3.323 ms | 3.955 ms | 165.46 ms |
|      Referencex5My | .NET Core 2.2 | .NET Core 2.2 |  51.68 ms | 0.361 ms | 0.320 ms |  51.69 ms |
|         intCodeJam | .NET Core 2.2 | .NET Core 2.2 |  35.83 ms | 0.311 ms | 0.275 ms |  35.74 ms |
|              intMy | .NET Core 2.2 | .NET Core 2.2 |  31.74 ms | 0.625 ms | 0.522 ms |  31.60 ms |
|       intx5CodeJam | .NET Core 2.2 | .NET Core 2.2 | 123.43 ms | 0.978 ms | 0.867 ms | 123.31 ms |
|            intx5My | .NET Core 2.2 | .NET Core 2.2 |  98.99 ms | 0.880 ms | 0.780 ms |  98.77 ms |
|        longCodeJam | .NET Core 2.2 | .NET Core 2.2 |  34.29 ms | 0.303 ms | 0.283 ms |  34.36 ms |
|             longMy | .NET Core 2.2 | .NET Core 2.2 |  30.74 ms | 0.154 ms | 0.128 ms |  30.77 ms |
|      longx5CodeJam | .NET Core 2.2 | .NET Core 2.2 | 124.48 ms | 2.454 ms | 2.826 ms | 123.33 ms |
|           longx5My | .NET Core 2.2 | .NET Core 2.2 | 101.79 ms | 0.816 ms | 0.763 ms | 101.74 ms |
Отредактировано 16.06.2020 9:48 StatujaLeha . Предыдущая версия . Еще …
Отредактировано 16.06.2020 7:14 StatujaLeha . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.