前回Enumerable.Range vs Observable.Range + Publishを試してみました。結果としては、当然なんですがRxのほうが遅いということになりました。それはそうとして、本来分配するタイプじゃないものを無理やり分配するんじゃなくて、もともと分配するように作られてるSubjectでやったら・・・?ということを思いついたので下記コードで試してみました。
using System; using System.Diagnostics; using System.Linq; using System.Reactive.Linq; using System.Reactive.Subjects; class Program { static void Main(string[] args) { var r = new Random(); // Enumerableで10万個の最小、最大、平均 Watch("Enumerable", () => { var array = Enumerable.Range(1, 1000000).Select(_ => r.Next(1000)).ToArray(); var min = array.Min(); var max = array.Max(); var avg = array.Average(); Console.WriteLine("min: {0}, max: {1}, avg: {2}", min, max, avg); }); // Observableで10万個の最小、最大、平均 Watch("Observable", () => { var o = Observable.Range(1, 1000000).Select(_ => r.Next(1000)).Publish(); o.Min().Zip(o.Max(), (min, max) => new { min, max }) .Zip(o.Average(), (x, avg) => new { x.min, x.max, avg }) .Subscribe(v => { Console.WriteLine("min: {0}, max: {1}, avg: {2}", v.min, v.max, v.avg); }); o.Connect(); }); // Observableで10万個の最小、最大、平均 Watch("Subject", () => { var o = new Subject<int>(); o.Min().Zip(o.Max(), (min, max) => new { min, max }) .Zip(o.Average(), (x, avg) => new { x.min, x.max, avg }) .Subscribe(v => { Console.WriteLine("min: {0}, max: {1}, avg: {2}", v.min, v.max, v.avg); }); foreach (var i in Enumerable.Range(1, 1000000).Select(_ => r.Next(1000))) { o.OnNext(i); } o.OnCompleted(); }); } static void Watch(string tag, Action action) { var s = Stopwatch.StartNew(); try { action(); } finally { s.Stop(); Console.WriteLine("{0} : {1}", tag, s.ElapsedMilliseconds); } } }
実行結果は下記の通りになりました。
min: 0, max: 999, avg: 499.402945 Enumerable : 68 min: 0, max: 999, avg: 499.205099 Observable : 7337 min: 0, max: 999, avg: 499.686331 Subject : 230
EnumerableとObservableで100倍近い差があるのは前回の通りなのですがSubjectでやった場合は230msと結構健闘してるように見えます。いいかも?