一直试图谷歌这个但是有点卡住了。
假设我们有一个触发事件的类,并且该事件可能同时被多个线程触发。
使用Observable.FromEventPattern,我们创建一个Observable,并订阅该事件。 Rx究竟如何管理多个同时被触发的事件?假设我们在不同的线程上快速连续发射了3个事件。它是否在内部排队,然后为每个队列同步调用Subscribe委托?假设我们订阅了一个线程池,我们是否仍然可以保证订阅将在时间上单独处理?
继续之后,让我们说对于每个事件,我们想要执行一个动作,但它是一个可能不是线程安全的方法,所以我们一次只希望一个线程在这个方法中。现在我看到我们可以使用EventLoop Scheduler,大概我们不需要对代码实现任何锁定?
另外,观察当前线程是一个选项吗?当前线程是事件被触发的线程,还是订阅设置的事件?即当前线程是否保证总是相同,或者可能有2个线程同时运行在方法中?
THX
PS:我把一个例子放在一起,但我似乎总是在我的订阅方法中使用相同的线程,即使我在线程池中观察到了这一点,这令人困惑:S
PSS:通过做一些实验,似乎如果没有指定Scheduler,那么RX将只在事件被触发的任何线程上执行,这意味着它同时处理几个。一旦我引入了一个调度程序,无论调度程序的类型是什么,它总是连续运行。奇怪:S答案 0 :(得分:2)
根据Rx Design Guidelines,一个观察者不应该同时调用观察者的OnNext
。在进行下一次呼叫之前,它将始终等待当前呼叫完成。所有Rx
方法都遵循此约定。更重要的是,他们认为你也尊重这个惯例。当您违反此条件时,您可能会遇到Observable
行为中的微妙错误。
如果您的源数据不符合此约定(即它可以同时生成数据),那么它们会提供Synchronize。
Observable.FromEventPattern
假设您不会触发并发事件,因此不会阻止并发下游通知。如果您打算同时从多个线程触发事件,请使用Synchronize()
作为FromEventPattern
后执行的第一个操作:
// this will get you in trouble if your event source might fire events concurrently.
var events = Observable.FromEventPattern(...).Select(...).GroupBy(...);
// this version will protect you in that case.
var events = Observable.FromEventPattern(...).Synchronize().Select(...).GroupBy(...);
现在所有下游运营商(以及最终的观察者)都受到保护,不受Rx设计指南所承诺的并发通知的影响。 Synchronize
使用简单的互斥锁(又称lock
语句)。没有奇特的排队或任何东西。如果一个线程尝试引发一个事件而另一个线程已经引发它,则第二个线程将阻塞,直到第一个线程完成。
答案 1 :(得分:0)
除了使用Synchronize的建议之外,阅读Intro to Rx section on scheduling and threading也许值得。它涵盖了不同的调度程序及其与线程的关系,以及ObserveOn和SubscribeOn之间的差异等。
答案 2 :(得分:0)
如果你有几个生产者,那么有一些RX方法可以用线程安全的方式组合它们
用于将相同类型事件的流组合到单个流中
Observable.Merge
使用选择器将不同类型事件的流组合成单个流,以将每个流上的最新值转换为新值。
Observable.CombineLatest
例如合并来自不同来源的股票价格
IObservable<StockPrice> source0;
IObservable<StockPrice> source1;
IObservable<StockPrice> combinedSources = source0.Merge(source1);
每次点击时或在当前位置创建气球
IObservable<ClickEvent> clicks;
IObservable<Position> position;
IObservable<Balloons> balloons = clicks
.CombineLatest
( positions
, (click,position)=>new Balloon(position.X, position.Y)
);
为了使这与你的问题特别相关,你说有一个类结合了来自不同线程的事件。然后我将使用Observable.Merge来组合各个事件源并将其作为主类的Observable公开。
顺便说一句,如果您的线程实际上是触发事件的任务,说它们已经在这里完成了一个有趣的模式
IObservable<Job> jobSource;
IObservable<IObservable<JobResult>> resultTasks = jobSource
.Select(job=>Observable.FromAsync(cancelationToken=>DoJob(token,job)));
IObservable<JobResult> results = resultTasks.Merge();
正在发生的事情是你正在获得一系列工作。从你正在创建异步任务流(尚未运行)的作业中。然后,合并运行任务并收集结果。它是mapreduce算法的一个例子。如果observable取消订阅(即取消),取消令牌可用于取消运行异步任务