J'évalue Rx pour un projet de plate-forme de négociation qui devra traiter des milliers de messages par seconde. La plate-forme existante possède un système de routage d'événements complexe (délégués de multidiffusion) qui répond à ces messages et effectue de nombreux traitements ultérieurs.Les extensions réactives semblent très lentes - est-ce que je fais quelque chose de mal?
J'ai regardé les extensions réactives pour les avantages évidents, mais j'ai remarqué qu'il est un peu plus lent, habituellement 100 fois plus lent.
J'ai créé un test unitaire pour illustrer ceci qui exécute un incrément simple d'un million de fois, en utilisant divers arômes Rx et un test de "contrôle" de délégué direct.
Voici les résultats:
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
Comme vous pouvez le voir, toutes les méthodes Rx sont environ 100 fois plus lent qu'un équivalent délégué. Évidemment Rx fait beaucoup sous les couvertures qui seront utiles dans un exemple plus complexe, mais cela semble incroyablement lent.
Est-ce normal ou mes hypothèses de test sont-elles invalides? Code nunit pour ce qui précède ci-dessous -
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 n'utilise pas l'argument 'scheduler', donc je suis surpris que vous obteniez des résultats différents. – dtb
Et pourquoi utilisez-vous un sujet au lieu de souscrire l'action directement à l'observable? Les sujets d'Afaik font beaucoup de choses sous couverture, vous devriez donc vérifier si le fait de les enlever fait une différence. – dtb
Je suis surpris que le ObservableRangeTest soit * vraiment * mauvais, même comparé aux tests avec sujet. Wtf? – dtb