Estoy evaluando Rx para un proyecto de plataforma comercial que necesitará procesar miles de mensajes por segundo. La plataforma existente tiene un sistema complejo de enrutamiento de eventos (delegados de multidifusión) que responde a estos mensajes y realiza una gran cantidad de procesamiento posterior.Las extensiones reactivas parecen muy lentas. ¿Estoy haciendo algo mal?
He examinado las extensiones reactivas para ver los beneficios obvios, pero noté que es algo más lento, normalmente 100 veces más lento.
He creado una prueba unitaria para demostrar esto que ejecuta un simple incremento de 1 millón de veces, usando varios sabores Rx y una prueba de "control" de delegado directo.
Éstos son los resultados:
Delegate - (1000000) - 00:00:00.0410000
Observable.Range() - (1000000) - 00:00:04.8760000
Subject.Subscribe() - NewThread - (1000000) - 00:00:02.7630000
Subject.Subscribe() - CurrentThread - (1000000) - 00:00:03.0280000
Subject.Subscribe() - Immediate - (1000000) - 00:00:03.0030000
Subject.Subscribe() - ThreadPool - (1000000) - 00:00:02.9800000
Subject.Subscribe() - Dispatcher - (1000000) - 00:00:03.0360000
Como se puede ver, todos los métodos son Rx ~ 100 veces más lento que un delegado equivalente. Obviamente, Rx está haciendo muchas cosas bajo las coberturas que serán útiles en un ejemplo más complejo, pero esto parece increíblemente lento.
¿Es esto normal o mis hipótesis de prueba son inválidas? código Nunit de lo anterior abajo -
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using NUnit.Framework;
using System.Concurrency;
namespace RxTests
{
[TestFixture]
class ReactiveExtensionsBenchmark_Tests
{
private int counter = 0;
[Test]
public void ReactiveExtensionsPerformanceComparisons()
{
int iterations = 1000000;
Action<int> a = (i) => { counter++; };
DelegateSmokeTest(iterations, a);
ObservableRangeTest(iterations, a);
SubjectSubscribeTest(iterations, a, Scheduler.NewThread, "NewThread");
SubjectSubscribeTest(iterations, a, Scheduler.CurrentThread, "CurrentThread");
SubjectSubscribeTest(iterations, a, Scheduler.Immediate, "Immediate");
SubjectSubscribeTest(iterations, a, Scheduler.ThreadPool, "ThreadPool");
SubjectSubscribeTest(iterations, a, Scheduler.Dispatcher, "Dispatcher");
}
public void ObservableRangeTest(int iterations, Action<int> action)
{
counter = 0;
long start = DateTime.Now.Ticks;
Observable.Range(0, iterations).Subscribe(action);
OutputTestDuration("Observable.Range()", start);
}
public void SubjectSubscribeTest(int iterations, Action<int> action, IScheduler scheduler, string mode)
{
counter = 0;
var eventSubject = new Subject<int>();
var events = eventSubject.SubscribeOn(scheduler); //edited - thanks dtb
events.Subscribe(action);
long start = DateTime.Now.Ticks;
Enumerable.Range(0, iterations).ToList().ForEach
(
a => eventSubject.OnNext(1)
);
OutputTestDuration("Subject.Subscribe() - " + mode, start);
}
public void DelegateSmokeTest(int iterations, Action<int> action)
{
counter = 0;
long start = DateTime.Now.Ticks;
Enumerable.Range(0, iterations).ToList().ForEach
(
a => action(1)
);
OutputTestDuration("Delegate", start);
}
/// <summary>
/// Output helper
/// </summary>
/// <param name="test"></param>
/// <param name="duration"></param>
public void OutputTestDuration(string test, long duration)
{
Debug.WriteLine(string.Format("{0, -40} - ({1}) - {2}", test, counter, ElapsedDuration(duration)));
}
/// <summary>
/// Test timing helper
/// </summary>
/// <param name="elapsedTicks"></param>
/// <returns></returns>
public string ElapsedDuration(long elapsedTicks)
{
return new TimeSpan(DateTime.Now.Ticks - elapsedTicks).ToString();
}
}
}
SubjectSubscribeTest no usa el argumento 'scheduler', así que me sorprende que en realidad obtengas resultados diferentes. – dtb
¿Y por qué estás usando un tema en lugar de suscribir la acción directamente al observable? Los sujetos de Afaik hacen bastante bajo la cobertura, por lo que debes comprobar si eliminarlos hace la diferencia. – dtb
Me sorprende que el ObservableRangeTest tenga un rendimiento * realmente * malo, incluso en comparación con las pruebas con el tema. Wtf? – dtb