2015-04-01 43 views
1

在我下面的例子中,我有2个主题和_primarySubject总是调用之前,_secondarySubject是保证在次回调之前接收主回调的用户?测试简单的测试似乎是说是或通过侥幸?由呼叫顺序交叉多个Rx主题保证排序?

如果这是侥幸,我该如何更改代码以保证顺序,正如我在这里所描述的。

非常感谢。

public class EventGenerator 
{ 
    ISubject<string> _primarySubject = new Subject<string>(); 
    ISubject<int> _secondarySubject = new Subject<int>(); 
    private int i; 
    public void SendEvent(string message) 
    { 
     _primarySubject.OnNext(message); 
     _secondarySubject.OnNext(i++); 
    } 

    public IObservable<string> GetPrimaryStream() 
    { 
     return _primarySubject; 
    } 

    public IObservable<int> GetSecondaryStream() 
    { 
     return _secondarySubject; 
    } 
} 

public class EventSubscriber 
{ 
    private static IScheduler StaticFakeGUIThread = new EventLoopScheduler(x => new Thread(x) { Name = "GUIThread" }); 

    private readonly int _id; 
    public EventSubscriber(int id, EventGenerator eventGenerator) 
    { 
     _id = id; 
     eventGenerator.GetPrimaryStream().ObserveOn(StaticFakeGUIThread).Subscribe(OnPrimaryEvent); 
     eventGenerator.GetSecondaryStream().ObserveOn(StaticFakeGUIThread).Subscribe(OnSecondaryEvent); 
    } 

    private void OnPrimaryEvent(String eventMsg) 
    { 
     string msg = eventMsg; 
    } 

    private void OnSecondaryEvent(int i) 
    { 
     int msg = i; 
    } 
} 

[TestFixture] 
public class EventGeneratorTest 
{ 
    [Test] 
    public void Test() 
    { 
     EventGenerator eg = new EventGenerator(); 

     EventSubscriber s1 = new EventSubscriber(1,eg); 
     EventSubscriber s2 = new EventSubscriber(2, eg); 

     eg.SendEvent("A"); 
     eg.SendEvent("B"); 
    } 
} 

回答

1

一般来说,Rx并没有对不同观察流的相对排序做出很多保证。排序取决于RX以外的许多因素。

在您的具体情况,订货保证:

  1. 既然你触发你的拍摄对象同步有序,保证了他们的直接订阅(.ObserveOn(StaticFakeUIThread))才能被触发。
  2. 由于您对ObserveOn这两个呼叫都使用相同的调度程序实例,因此可以保证在观察次要流事件之前安排观察主要流事件,并且这两个观测值将使用相同的调度程序进行调度
  3. 由于您的计划程序是EventLoopScheduler,因此可以保证它不会同时运行计划任务,而是会按照计划的顺序运行它们。

因此,您的观察确实会按顺序运行。

更换EventLoopSchedulerTaskPoolSchedulerThreadPoolScheduler,或Scheduler.Default而且将不再是在两个流的相对顺序任何保证,因为这些调度允许concurrenly运行这两个计划的任务。

1

这一切都取决于你“保证”的含义。当前Rx的实现以及编写的代码是这样的,调用顺序将始终如您所见 - 然而,没有公布规则来管理该行为并保证它。

您的代码编写方式对于使用两个主题 - 或实际上是两个订阅没有特别的优势,因为处理程序是在同一个线程上调用的。只需使用结合事件的单个主题即可获得所需的保证 - 为此使用自定义类型。为方便起见,我用一个元组:

ISubject<Tuple<string,int>> _subject = new Subject<Tuple<string,int>>(); 
private int i; 
public void SendEvent(string message) 
{ 
    _subject.OnNext(Tuple.Create(message,i++)); 
} 

而且订阅:

private void OnEvent(Tuple<String,int> eventMsg) 
{ 
    string msgText = eventMsg.Item1; 
    int msgNum = eventMsg.Item2; 
} 

不管调度等我猜想一定有你的问题更多一些令人信服的理由,这向你保证 - 但否则这是更有效的。

如果您只是想使用计数器顺便说一句,那么有Select的重载,为您引入一个基于0的事件索引计数器。