我正在尝试查看如何使用 Rx 将多个可观察事件流式传输到一组事件中。但是当我运行下面的代码时,我得到了一个异常。那么这是否意味着多个观察者总是因为违反 Rx 语法而容易出现异常?我的意思是,如果这两个观察者中的两个偶然同时生成一个事件(任何两个可观察量都有同时生成的可能性(,它应该给出一个例外。
DateTimeOffset start;
object sync = new object();
var subject = new Subject<long>();
var observer = Observer.Create<long>(c =>
{
lock (sync)
{
Console.WriteLine(c);
}
})
;
var observable1 = Observable.Interval(TimeSpan.FromSeconds(2));
var observable2 = Observable.Interval(TimeSpan.FromSeconds(5));
var observable3 = Observable.Never<long>().Timeout
(start = DateTimeOffset.Now.AddSeconds(15),
(new long[] { 1 }).ToObservable());
var observable4 = Observable.Never<long>().Timeout(start);
observable1.Subscribe(observer);
observable2.Subscribe(observer);
observable3.Subscribe(observer);
observable4.Subscribe(observer);
Thread.Sleep(20000);
感谢吉迪恩的解释。这是我得到的例外。你是对的,这是一个超时异常。这是一个编码错误。谢谢。
System.TimeoutException: The operation has timed out.
at System.Reactive.Observer.<Create>b__8[T](Exception e)
at System.Reactive.AnonymousObserver`1.Error(Exception exception)
at System.Reactive.AbstractObserver`1.OnError(Exception error)
at System.Reactive.Subjects.Subject`1.OnError(Exception error)
at System.Reactive.AnonymousObservable`1.AutoDetachObserver.Error(Exception e
xception)
at System.Reactive.AbstractObserver`1.OnError(Exception error)
at System.Reactive.AnonymousObservable`1.AutoDetachObserver.Error(Exception e
xception)
at System.Reactive.AbstractObserver`1.OnError(Exception error)
at System.Reactive.Linq.Observable.<>c__DisplayClass28c`1.<>c__DisplayClass28
e.<Throw>b__28b()
at System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action
action)
at System.Reactive.Concurrency.ImmediateScheduler.Schedule[TState](TState sta
te, Func`3 action)
at System.Reactive.Concurrency.Scheduler.Schedule(IScheduler scheduler, Actio
n action)
at System.Reactive.Linq.Observable.<>c__DisplayClass28c`1.<Throw>b__28a(IObse
rver`1 observer)
at System.Reactive.AnonymousObservable`1.<>c__DisplayClass1.<Subscribe>b__0()
at System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action
action)
at System.Reactive.Concurrency.ScheduledItem`2.InvokeCore()
at System.Reactive.Concurrency.ScheduledItem`1.Invoke()
at System.Reactive.Concurrency.CurrentThreadScheduler.Trampoline.Run()
at System.Reactive.Concurrency.CurrentThreadScheduler.Schedule[TState](TState
state, TimeSpan dueTime, Func`3 action)
at System.Reactive.Concurrency.CurrentThreadScheduler.Schedule[TState](TState
state, Func`3 action)
at System.Reactive.Concurrency.Scheduler.Schedule(IScheduler scheduler, Actio
n action)
at System.Reactive.AnonymousObservable`1.Subscribe(IObserver`1 observer)
at System.Reactive.Linq.Observable.<>c__DisplayClass543`1.<>c__DisplayClass54
5.<Timeout>b__53f()
at System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action
action)
at System.Reactive.Concurrency.ThreadPoolScheduler.<>c__DisplayClass8`1.<Sche
dule>b__6(Object _)
at System.Threading._TimerCallback.TimerCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C
ontextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading._TimerCallback.PerformTimerCallback(Object state)
是的,观察者可以侦听多个可观察量。 最好的例子是Merge
运算符。 内置运算符将全部遵循 RX 语法,并且通常会在不遵循 RX 语法的源上强制执行它。
你从Observer.Create
得到的IObserver
就是这样一种情况。 一旦调用了 OnError 或 OnComplete,它将忽略将来对 OnNext 的任何调用。 这确实意味着,使用同一观察器订阅一个可观察量,然后在第一个可观察量之后订阅另一个可观察量将不起作用,因为来自第一个可观察量的终止消息将导致观察者忽略来自第二个可观察量的消息。 为了解决这个问题,像 Merge
、Concat
和 OnErrorResumeNext
这样的运算符(等等(在内部使用多个观察器,并且不会将完成消息(OnError 和/或 OnCompleted 取决于运算符的语义(从最后一个可观察对象传递到外部观察器。
没有提到您得到的异常,但我猜这是来自您从observable4
获得的超时的错误。 如果未提供另一个用于超时的可观察量,则会调用观察者的OnError
,并且不采用错误处理程序的Subscribe
和Observer.Create
重载的默认OnError
是简单地引发异常。
虽然这显然是示例/测试代码,但我确实想指出,即使您不再收到传递给OnNext
的消息,所有其他可观察量在此异常之后仍会继续运行。 使用Merge
为您跟踪此内容,或者跟踪描述中的所有一次性用品,并在完成消息通过时自行处理它们。 CompositeDisposable
(System.Reactive.Disposables
(对此有好处。
你真的不应该在这里使用锁,但如果你真的希望它工作,你可以这样做:
var x = Observable.Create<T>(subj => { /* Fill it in*/ })
.Multicast(new Subject<T>());
// Set up your subscriptions Here!
// When you call the Connect, whatever is in the Observable.Create will be called
x.Connect();
如果你想更安全,你可以通过使用重播主题而不是主题来"重播"创建的结果,以便在将来的订阅中重播(而对于主题,连接后的订阅者将一无所获(