C# 观察和订阅-工作正在进行的地方
根据阅读此问题:C# 观察和订阅-工作正在进行的地方,c#,.net,system.reactive,C#,.net,System.reactive,根据阅读此问题: ObserveOn设置执行Subscribe处理程序中代码的位置: stream.Subscribe(=>{//这里的代码}) SubscribeOn方法设置在哪个线程上完成流的设置 我被引导去理解,如果没有显式地设置它们,那么就使用TaskPool 现在我的问题是,假设我这样做: Observable.Interval(new Timespan(0, 0, 1)) .Where(t => predicate(t)) .Select
ObserveOn
设置执行Subscribe
处理程序中代码的位置:
stream.Subscribe(=>{//这里的代码})代码>
SubscribeOn
方法设置在哪个线程上完成流的设置
我被引导去理解,如果没有显式地设置它们,那么就使用TaskPool
现在我的问题是,假设我这样做:
Observable.Interval(new Timespan(0, 0, 1))
.Where(t => predicate(t))
.SelectMany(t => lots_of(t))
.ObserveOnDispatcher()
.Subscribe(t => some_action(t));
Calling from Thread: 1
Timer: Observable obtained on Thread: 1
ObserveOn: Observable obtained on Thread: 1
ObserveOn: Subscribed to on Thread: 1
Timer: Subscribed to on Thread: 1
Timer: Subscription completed.
ObserveOn: Subscription completed.
Subscribe returned
Blocking the dispatcher
Timer: OnNext(0) on Thread: 2
Timer: OnCompleted() on Thread: 2
Unblocked
ObserveOn: OnNext(0) on Thread: 1
ObserveOn: OnCompleted() on Thread: 1
鉴于调度程序上正在执行一些动作,执行的Where
谓词和SelectMany
lots\u
在哪里
总结
subscribebeon
拦截对IObservable
的单个方法的调用,即Subscribe
,以及对Subscribe
返回的IDisposable
句柄上的Dispose
的调用
ObserveOn
拦截对IObserver
方法的调用,这些方法是OnNext
,OnCompleted
和OnError
- 这两种方法都会导致在指定的计划程序上进行相应的调用李>
分析与演示
声明
ObserveOn设置订阅处理程序中代码的位置
执行:
这比帮助更令人困惑。您所指的“订阅处理程序”实际上是一个OnNext
处理程序。请记住,IObservable
的Subscribe
方法接受具有OnNext
、OnCompleted
和OnError
方法的IObserver
,但扩展方法提供了方便的重载,可以接受lambda并为您构建IObserver
实现
让我用这个词吧;我认为“Subscribe handler”是在调用Subscribe
时调用的可观察对象中的代码。这样,上面的描述更接近于SubscribeOn
的目的
订阅
SubscribeOn
导致可观察对象的Subscribe
方法在指定的计划程序或上下文上异步执行。当您不想从正在运行的任何线程对一个可观察的对象调用Subscribe
方法时,您可以使用它,这通常是因为它可以长期运行,并且您不想阻止调用线程
当您调用Subscribe
时,您调用的是一个可观察对象,它可能是一长串可观察对象的一部分。只有SubscribeOn
应用于其影响的可观察值。现在可能会出现这样的情况,即链中的所有可观察对象将立即在同一线程上订阅,但情况并非如此。例如,考虑Concat
,它只在前一个流完成后订阅每个后续流,通常这将发生在前一个流调用OnCompleted
的任何线程上
因此,SubscribeOn
位于对Subscribe
的调用和要订阅的可观察对象之间,拦截调用并使其异步
它还影响订阅的处理Subscribe
返回用于取消订阅的IDisposable
句柄SubscribeOn
确保在提供的计划程序上计划调用Dispose
当试图理解SubscribeOn
所做的事情时,一个常见的混淆点是,可观察对象的Subscribe
处理程序可能会在同一线程上调用OnNext
、OnCompleted
或OnError
。但是,其目的不是影响这些通话。流在Subscribe
方法返回之前完成并不罕见<代码>可观察。例如,Return
执行此操作。让我们看一下。
如果使用我编写的方法并运行以下代码:
Console.WriteLine("Calling from Thread: " + Thread.CurrentThread.ManagedThreadId);
var source = Observable.Return(1).Spy("Return");
source.Subscribe();
Console.WriteLine("Subscribe returned");
您将获得此输出(当然线程id可能会有所不同):
您可以看到整个订阅处理程序在同一个线程上运行,并在返回之前完成
让我们使用SubscribeOn
异步运行它。我们将监视返回
可观察和订阅
可观察:
Console.WriteLine("Calling from Thread: " + Thread.CurrentThread.ManagedThreadId);
var source = Observable.Return(1).Spy("Return");
source.SubscribeOn(Scheduler.Default).Spy("SubscribeOn").Subscribe();
Console.WriteLine("Subscribe returned");
此输出(由我添加的行号):
01-主要方法在线程1上运行
02-在调用线程上评估可观察的返回。我们只是在这里得到了IObservable
,还没有任何订阅
03-在调用线程上评估可观察的SubscribeOn
04-现在我们最后调用Subscribe
方法subscribebeon
05-Subscribe
方法异步完成
06-。。。线程1返回到main方法这是SubscribeOn的实际效果强>
07-同时,SubscribeOn
在默认调度程序上安排了一个调用,以Return
。这里它是在线程2上接收的
08-正如Return
所做的那样,它在Subscribe
线程上调用OnNext
09-而SubscribeOn
现在只是一个过客
10,11-与未完成的<代码>相同
12-最后一个返回订阅处理程序完成
希望这能澄清订阅的目的和效果
观察
如果将SubscribeOn
视为将调用传递给不同线程的Subscribe
方法的拦截器,则ObserveOn
执行相同的任务,但
01 Calling from Thread: 1
02 Return: Observable obtained on Thread: 1
03 SubscribeOn: Observable obtained on Thread: 1
04 SubscribeOn: Subscribed to on Thread: 1
05 SubscribeOn: Subscription completed.
06 Subscribe returned
07 Return: Subscribed to on Thread: 2
08 Return: OnNext(1) on Thread: 2
09 SubscribeOn: OnNext(1) on Thread: 2
10 Return: OnCompleted() on Thread: 2
11 SubscribeOn: OnCompleted() on Thread: 2
12 Return: Subscription completed.
Console.WriteLine("Calling from Thread: " + Thread.CurrentThread.ManagedThreadId);
var source = Observable.Return(1).Spy("Return");
source.Subscribe();
Console.WriteLine("Subscribe returned");
Calling from Thread: 1
Return: Observable obtained on Thread: 1
Return: Subscribed to on Thread: 1
Return: OnNext(1) on Thread: 1
Return: OnCompleted() on Thread: 1
Return: Subscription completed.
Subscribe returned
Console.WriteLine("Calling from Thread: " + Thread.CurrentThread.ManagedThreadId);
var source = Observable.Return(1).Spy("Return");
source.ObserveOn(Scheduler.Default).Spy("ObserveOn").Subscribe();
Console.WriteLine("Subscribe returned");
01 Calling from Thread: 1
02 Return: Observable obtained on Thread: 1
03 ObserveOn: Observable obtained on Thread: 1
04 ObserveOn: Subscribed to on Thread: 1
05 Return: Subscribed to on Thread: 1
06 Return: OnNext(1) on Thread: 1
07 ObserveOn: OnNext(1) on Thread: 2
08 Return: OnCompleted() on Thread: 1
09 Return: Subscription completed.
10 ObserveOn: Subscription completed.
11 Subscribe returned
12 ObserveOn: OnCompleted() on Thread: 2
Console.WriteLine("Calling from Thread: " + Thread.CurrentThread.ManagedThreadId);
var source = Observable.Timer(TimeSpan.FromSeconds(1)).Spy("Timer");
source.Subscribe();
Console.WriteLine("Subscribe returned");
Calling from Thread: 1
Timer: Observable obtained on Thread: 1
Timer: Subscribed to on Thread: 1
Timer: Subscription completed.
Subscribe returned
Timer: OnNext(0) on Thread: 2
Timer: OnCompleted() on Thread: 2
Console.WriteLine("Calling from Thread: " + Thread.CurrentThread.ManagedThreadId);
var source = Observable.Timer(TimeSpan.FromSeconds(1)).Spy("Timer");
source.SubscribeOn(NewThreadScheduler.Default).Spy("SubscribeOn").Subscribe();
Console.WriteLine("Subscribe returned");
Calling from Thread: 1
Timer: Observable obtained on Thread: 1
SubscribeOn: Observable obtained on Thread: 1
SubscribeOn: Subscribed to on Thread: 1
SubscribeOn: Subscription completed.
Subscribe returned
Timer: Subscribed to on Thread: 2
Timer: Subscription completed.
Timer: OnNext(0) on Thread: 3
SubscribeOn: OnNext(0) on Thread: 3
Timer: OnCompleted() on Thread: 3
SubscribeOn: OnCompleted() on Thread: 3
var dispatcher = Dispatcher.CurrentDispatcher;
Console.WriteLine("Calling from Thread: " + Thread.CurrentThread.ManagedThreadId);
var source = Observable.Timer(TimeSpan.FromSeconds(1)).Spy("Timer");
source.ObserveOnDispatcher().Spy("ObserveOn").Subscribe();
Console.WriteLine("Subscribe returned");
Calling from Thread: 1
Timer: Observable obtained on Thread: 1
ObserveOn: Observable obtained on Thread: 1
ObserveOn: Subscribed to on Thread: 1
Timer: Subscribed to on Thread: 1
Timer: Subscription completed.
ObserveOn: Subscription completed.
Subscribe returned
Timer: OnNext(0) on Thread: 2
ObserveOn: OnNext(0) on Thread: 1
Timer: OnCompleted() on Thread: 2
ObserveOn: OnCompleted() on Thread: 1
var dispatcher = Dispatcher.CurrentDispatcher;
Console.WriteLine("Calling from Thread: " + Thread.CurrentThread.ManagedThreadId);
var source = Observable.Timer(TimeSpan.FromSeconds(1)).Spy("Timer");
source.ObserveOnDispatcher().Spy("ObserveOn").Subscribe();
Console.WriteLine("Subscribe returned");
Console.WriteLine("Blocking the dispatcher");
Thread.Sleep(2000);
Console.WriteLine("Unblocked");
Calling from Thread: 1
Timer: Observable obtained on Thread: 1
ObserveOn: Observable obtained on Thread: 1
ObserveOn: Subscribed to on Thread: 1
Timer: Subscribed to on Thread: 1
Timer: Subscription completed.
ObserveOn: Subscription completed.
Subscribe returned
Blocking the dispatcher
Timer: OnNext(0) on Thread: 2
Timer: OnCompleted() on Thread: 2
Unblocked
ObserveOn: OnNext(0) on Thread: 1
ObserveOn: OnCompleted() on Thread: 1
using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Linq;
namespace SchedulerExample
{
class Program
{
static void Main(string[] args)
{
var mydata = new[] {"A", "B", "C", "D", "E"};
var observable = Observable.Create<string>(observer =>
{
Console.WriteLine("Observable.Create");
return mydata.ToObservable().
Subscribe(observer);
});
observable.
SubscribeOn(new MyScheduler(ConsoleColor.Red)).
ObserveOn(new MyScheduler(ConsoleColor.Blue)).
Subscribe(s => Console.WriteLine("OnNext {0}", s));
Console.ReadKey();
}
}
}
using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
namespace SchedulerExample
{
class MyScheduler : IScheduler
{
private readonly ConsoleColor _colour;
public MyScheduler(ConsoleColor colour)
{
_colour = colour;
}
public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
return Execute(state, action);
}
private IDisposable Execute<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
var tmp = Console.ForegroundColor;
Console.ForegroundColor = _colour;
action(this, state);
Console.ForegroundColor = tmp;
return Disposable.Empty;
}
public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
{
throw new NotImplementedException();
}
public DateTimeOffset Now
{
get { return DateTime.UtcNow; }
}
}
}