在我下面的示例中,我有2个主题,_primarySubject总是在_secondarySubject之前调用,订阅者保证在次要回调之前接收主要回调?测试简单的测试似乎是肯定的,或者这是侥幸吗?
如果这是侥幸的话,我怎么能改变代码来保证订单,就像我在这里描述的那样。
非常感谢。
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");
}
}
答案 0 :(得分:1)
通常,Rx对不同可观察流的相对排序没有很多保证。订购取决于RX无法控制的许多因素。
在您的具体情况下,保证订购:
.ObserveOn(StaticFakeUIThread)
)。ObserveOn
的两次调用都使用相同的调度程序实例,因此可以保证在观察辅助流事件之前调度主流事件的观察结果,并且将使用相同的调度程序EventLoopScheduler
,因此可以保证它不会同时运行计划任务,而是按照计划的顺序运行它们。因此,您的观察确实会按顺序进行。
将EventLoopScheduler
替换为TaskPoolScheduler
,ThreadPoolScheduler
或Scheduler.Default
,并且将不再保证两个流的相对排序,因为这些调度程序被允许同时运行两个计划任务。
答案 1 :(得分: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;
}
无论调度程序如何,这都可以为您提供保证。我怀疑您的问题必须有一些更有说服力的理由 - 否则这会更有效。
如果您只是想使用计数器btw,那么Select
的重载会为您引入基于0的事件索引计数器。
答案 2 :(得分:0)
理论上,一切都应该按顺序运作。实际上,EventLoopScheduler中存在一个错误,如果队列正在挨饿,它会破坏顺序。
在此处查看问题 https://github.com/Reactive-Extensions/Rx.NET/issues/455