浏览代码

Ix: Improve the performance of Buffer exact/skip mode

Dávid Karnok 7 年之前
父节点
当前提交
4cf09e8445

+ 5 - 3
Ix.NET/Source/Benchmarks.System.Interactive/BufferCountBenchmark.cs

@@ -13,12 +13,14 @@ namespace Benchmarks.System.Interactive
     [MemoryDiagnoser]
     public class BufferCountBenchmark
     {
+        [Params(1, 10, 100, 1000, 10000, 100000, 1000000)]
+        public int N;
         private IList<int> _store;
 
         [Benchmark]
         public void Exact()
         {
-            Enumerable.Range(1, 1000)
+            Enumerable.Range(1, N)
                 .Buffer(1)
                 .Subscribe(v => Volatile.Write(ref _store, v));
         }
@@ -26,7 +28,7 @@ namespace Benchmarks.System.Interactive
         [Benchmark]
         public void Skip()
         {
-            Enumerable.Range(1, 1000)
+            Enumerable.Range(1, N)
                 .Buffer(1, 2)
                 .Subscribe(v => Volatile.Write(ref _store, v));
         }
@@ -34,7 +36,7 @@ namespace Benchmarks.System.Interactive
         [Benchmark]
         public void Overlap()
         {
-            Enumerable.Range(1, 1000)
+            Enumerable.Range(1, N)
                 .Buffer(2, 1)
                 .Subscribe(v => Volatile.Write(ref _store, v));
         }

+ 68 - 2
Ix.NET/Source/System.Interactive/Buffer.cs

@@ -27,7 +27,7 @@ namespace System.Linq
                 throw new ArgumentOutOfRangeException(nameof(count));
             }
 
-            return source.Buffer_(count, count);
+            return BufferExact(source, count);
         }
 
         /// <summary>
@@ -55,6 +55,15 @@ namespace System.Linq
                 throw new ArgumentOutOfRangeException(nameof(skip));
             }
 
+            if (count == skip)
+            {
+                return BufferExact(source, count);
+            }
+            if (count < skip)
+            {
+                return BufferSkip(source, count, skip);
+            }
+
             return source.Buffer_(count, skip);
         }
 
@@ -89,6 +98,63 @@ namespace System.Linq
                 yield return buffers.Dequeue();
             }
         }
+
+        private static IEnumerable<IList<TSource>> BufferExact<TSource>(IEnumerable<TSource> source, int count)
+        {
+            IList<TSource> buffer = null;
+
+            foreach (var v in source)
+            {
+                if (buffer == null)
+                {
+                    buffer = new List<TSource>();
+                }
+
+                buffer.Add(v);
+                if (buffer.Count == count)
+                {
+                    yield return buffer;
+                    buffer = null;
+                }
+            }
+
+            if (buffer != null)
+            {
+                yield return buffer;
+            }
+        }
+
+        private static IEnumerable<IList<TSource>> BufferSkip<TSource>(IEnumerable<TSource> source, int count, int skip)
+        {
+            IList<TSource> buffer = null;
+
+            var index = 0;
+
+            foreach (var v in source)
+            {
+                if (index == 0)
+                {
+                    buffer = new List<TSource>();
+                }
+
+                buffer?.Add(v);
+                if (++index == count)
+                {
+                    yield return buffer;
+                    buffer = null;
+                }
+
+                if (index == skip)
+                {
+                    index = 0;
+                }
+            }
+
+            if (buffer != null)
+            {
+                yield return buffer;
+            }
+        }
     }
 
     /// <summary>
@@ -98,4 +164,4 @@ namespace System.Linq
     public interface IBuffer<out T> : IEnumerable<T>, IDisposable
     {
     }
-}
+}