// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT License. // See the LICENSE file in the project root for more information. using System; using System.Reactive.Linq; using BenchmarkDotNet.Attributes; namespace Benchmarks.System.Reactive { /// /// Completion of a wide fan-out/in scenario. /// /// /// /// This was added to address https://github.com/dotnet/reactive/issues/2005 in which completion /// takes longer and longer to handle as the number of groups increases. /// /// /// The queries in this benchmark represent the common 'fan out/in' pattern in Rx. It is often /// useful to split a stream into groups to enable per-group processing, and then to recombine /// the data back into a single stream. These benchmarks don't do any per-group processing, so /// they might look pointless, but we're trying to measure the minimum unavoidable overhead /// that any code using this technique will encounter. /// /// [MemoryDiagnoser] public class GroupByCompletion { private IObservable observable; [Params(200_000, 1_000_000)] public int NumberOfSamples { get; set; } [Params(10, 100, 1_000, 10_000, 100_000, 150_000, 200_000)] public int NumberOfGroups { get; set; } [GlobalSetup] public void GlobalSetup() { var data = new int[NumberOfSamples]; for (var i = 0; i < data.Length; ++i) { data[i] = i; } observable = data.ToObservable(); } [Benchmark] public void GroupBySelectMany() { var numberOfGroups = NumberOfGroups; observable!.GroupBy(value => value % numberOfGroups) .SelectMany(groupOfInts => groupOfInts) .Subscribe(intValue => { }); } [Benchmark] public void GroupByMerge() { var numberOfGroups = NumberOfGroups; observable!.GroupBy(value => value % numberOfGroups) .Merge() .Subscribe(intValue => { }); } } }