ComparisonBenchmark.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Reactive.Concurrency;
  8. using System.Reactive.Disposables;
  9. using System.Reactive.Linq;
  10. using System.Reactive.Subjects;
  11. using System.Threading;
  12. using BenchmarkDotNet.Attributes;
  13. namespace Benchmarks.System.Reactive
  14. {
  15. [MemoryDiagnoser]
  16. public class ComparisonBenchmark
  17. {
  18. [Params(1, 10, 100, 1000, 10000, 100000, 1000000)]
  19. public int N;
  20. private int _store;
  21. [Benchmark]
  22. public void ForLoopBaseLine()
  23. {
  24. var n = N;
  25. for (var i = 0; i < N; i++)
  26. {
  27. Volatile.Write(ref _store, i);
  28. }
  29. }
  30. [Benchmark]
  31. public void EnumerableBaseLine()
  32. {
  33. foreach (var v in Enumerable.Range(1, N))
  34. {
  35. Volatile.Write(ref _store, v);
  36. }
  37. }
  38. [Benchmark]
  39. public void Return()
  40. {
  41. Observable.Return(1).Subscribe(v => Volatile.Write(ref _store, v));
  42. }
  43. [Benchmark]
  44. public void Range()
  45. {
  46. Observable.Range(1, N).Subscribe(v => Volatile.Write(ref _store, v));
  47. }
  48. [Benchmark]
  49. public void Select()
  50. {
  51. Observable.Range(1, N)
  52. .Select(v => v + 1)
  53. .Subscribe(v => Volatile.Write(ref _store, v));
  54. }
  55. [Benchmark]
  56. public void SelectSelect()
  57. {
  58. Observable.Range(1, N)
  59. .Select(v => v + 1)
  60. .Select(v => v + 1)
  61. .Subscribe(v => Volatile.Write(ref _store, v));
  62. }
  63. [Benchmark]
  64. public void Where()
  65. {
  66. Observable.Range(1, 2 * N)
  67. .Where(v => (v & 1) != 0)
  68. .Subscribe(v => Volatile.Write(ref _store, v));
  69. }
  70. [Benchmark]
  71. public void WhereWhere()
  72. {
  73. Observable.Range(1, 4 * N)
  74. .Where(v => (v & 1) != 0)
  75. .Where(v => (v & 2) != 0)
  76. .Subscribe(v => Volatile.Write(ref _store, v));
  77. }
  78. [Benchmark]
  79. public void Take()
  80. {
  81. Observable.Range(1, 2 * N)
  82. .Take(N)
  83. .Subscribe(v => Volatile.Write(ref _store, v));
  84. }
  85. [Benchmark]
  86. public void Skip()
  87. {
  88. Observable.Range(1, 2 * N)
  89. .Skip(N)
  90. .Subscribe(v => Volatile.Write(ref _store, v));
  91. }
  92. [Benchmark]
  93. public void TakeUntil()
  94. {
  95. Observable.Range(1, N)
  96. .TakeUntil(Observable.Never<int>())
  97. .Subscribe(v => Volatile.Write(ref _store, v));
  98. }
  99. [Benchmark]
  100. public void ToObservable()
  101. {
  102. Enumerable.Range(1, N)
  103. .ToObservable()
  104. .Subscribe(v => Volatile.Write(ref _store, v));
  105. }
  106. [Benchmark]
  107. public void Concat()
  108. {
  109. var M = N - N / 2;
  110. Observable.Concat(
  111. Observable.Range(1, N),
  112. Observable.Range(1, M)
  113. )
  114. .Subscribe(v => Volatile.Write(ref _store, v));
  115. }
  116. [Benchmark]
  117. public void ConcatCrossMap()
  118. {
  119. var M = 1000 * 1000 / N;
  120. Observable.Concat(Observable.Range(1, N).Select(v => Observable.Range(v, M)))
  121. .Subscribe(v => Volatile.Write(ref _store, v));
  122. }
  123. [Benchmark]
  124. public void SelectManyCrossMap()
  125. {
  126. var M = 1000 * 1000 / N;
  127. Observable.Range(1, N).SelectMany(v => Observable.Range(v, M))
  128. .Subscribe(v => Volatile.Write(ref _store, v));
  129. }
  130. [Benchmark]
  131. public void MergeCrossMap()
  132. {
  133. var M = 1000 * 1000 / N;
  134. Observable.Merge(Observable.Range(1, N)
  135. .Select(v => Observable.Range(v, M))
  136. )
  137. .Subscribe(v => Volatile.Write(ref _store, v));
  138. }
  139. [Benchmark]
  140. public void AsyncSubjectPush()
  141. {
  142. var subj = new AsyncSubject<int>();
  143. subj.Subscribe(v => Volatile.Write(ref _store, v));
  144. var n = N;
  145. for (var i = 0; i < N; i++)
  146. {
  147. subj.OnNext(i);
  148. }
  149. subj.OnCompleted();
  150. }
  151. [Benchmark]
  152. public void SubjectPush()
  153. {
  154. var subj = new Subject<int>();
  155. subj.Subscribe(v => Volatile.Write(ref _store, v));
  156. var n = N;
  157. for (var i = 0; i < N; i++)
  158. {
  159. subj.OnNext(i);
  160. }
  161. subj.OnCompleted();
  162. }
  163. [Benchmark]
  164. public void AmbTwo()
  165. {
  166. Observable.Never<int>().Amb(Observable.Range(1, N))
  167. .Subscribe(v => Volatile.Write(ref _store, v));
  168. }
  169. [Benchmark]
  170. public void AmbThree()
  171. {
  172. Observable.Amb(Observable.Never<int>(), Observable.Never<int>(), Observable.Range(1, N))
  173. .Subscribe(v => Volatile.Write(ref _store, v));
  174. }
  175. [Benchmark]
  176. public void Timeout()
  177. {
  178. Observable.Range(1, N)
  179. .Timeout(TimeSpan.FromHours(1))
  180. .Subscribe(v => Volatile.Write(ref _store, v));
  181. }
  182. #pragma warning disable CS0618 // Type or member is obsolete
  183. [Benchmark]
  184. public void First()
  185. {
  186. Volatile.Write(ref _store, Observable.Range(1, N)
  187. .First());
  188. }
  189. [Benchmark]
  190. public void Last()
  191. {
  192. Volatile.Write(ref _store, Observable.Range(1, N)
  193. .Last());
  194. }
  195. #pragma warning restore CS0618 // Type or member is obsolete
  196. private IList<int> _bufferStore;
  197. [Benchmark]
  198. public void Buffer_Exact()
  199. {
  200. Observable.Range(1, 1000)
  201. .Buffer(1)
  202. .Subscribe(v => Volatile.Write(ref _bufferStore, v));
  203. }
  204. [Benchmark]
  205. public void Buffer_Skip()
  206. {
  207. Observable.Range(1, 1000)
  208. .Buffer(1, 2)
  209. .Subscribe(v => Volatile.Write(ref _bufferStore, v));
  210. }
  211. [Benchmark]
  212. public void Buffer_Overlap()
  213. {
  214. Observable.Range(1, 1000)
  215. .Buffer(2, 1)
  216. .Subscribe(v => Volatile.Write(ref _bufferStore, v));
  217. }
  218. [Benchmark]
  219. public void CurrentThreadSchedulerRepeated()
  220. {
  221. var n = N;
  222. var scheduler = CurrentThreadScheduler.Instance;
  223. for (var i = 0; i < n; i++)
  224. {
  225. scheduler.Schedule(i, (_, v) =>
  226. {
  227. Volatile.Write(ref _store, v);
  228. return Disposable.Empty;
  229. });
  230. }
  231. }
  232. [Benchmark]
  233. public void TakeLast()
  234. {
  235. Observable.Range(1, 2 * N).TakeLast(N)
  236. .Subscribe(v => Volatile.Write(ref _store, v));
  237. }
  238. [Benchmark]
  239. public void Repeat()
  240. {
  241. Observable.Repeat(1, N)
  242. .Subscribe(v => Volatile.Write(ref _store, v));
  243. }
  244. [Benchmark]
  245. public void ToList()
  246. {
  247. Observable.Repeat(1, N).ToList()
  248. .Subscribe(v => Volatile.Write(ref _bufferStore, v));
  249. }
  250. [Benchmark]
  251. public void Generate()
  252. {
  253. Observable.Generate(0, s => s < N, s => s + 1, s => s)
  254. .Subscribe(v => Volatile.Write(ref _store, v));
  255. }
  256. }
  257. }