返回当前线程观察

goo*_*nd0 0 c# concurrency system.reactive

我正在尝试在新线程上安排一个可观察对象,并将结果返回到当前线程上。

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Log("init");

            Observable.Return(0)
                .ObserveOn(NewThreadScheduler.Default)
                .Do(_ => Log("Do1 method"))
                .ObserveOn(CurrentThreadScheduler.Instance)
                .Do(_ => Log("Do2 method"))
                .Subscribe(_ => Log("subscribe method"));

            Console.ReadKey();
        }

        static void Log(string label)
        {
            Console.WriteLine("{0} on {1}", label, Thread.CurrentThread.ManagedThreadId);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我得到的结果:

init on 9
Do1 method on 10
Do2 method on 10
subscribe method on 10
Run Code Online (Sandbox Code Playgroud)

为什么 Do2 方法和 subscribe 方法在线程 #10 上而不是在线程 #9 上?我期待这个结果:

init on 9
Do1 method on 10
Do2 method on 9
subscribe method on 9
Run Code Online (Sandbox Code Playgroud)

Lee*_*ell 5

我可以看到您想要实现的目标,但这可能会很困难,因为您只是在同步线程上的控制台应用程序中运行。由于主控制台线程不是 EventLoop,Rx 如何能够“解锁”调用Console.ReadKey()、劫持线程执行Log方法,然后返回等待Console.ReadKey()

如果您在 GUI 应用程序中执行此操作,那么主线程将是某种 EventLoop,即 WPF/Silverlight 中的 Dispatcher。现在可以轻松地将控制权返回到“主线程” -ObserveOn(_dispatcherScheduler)捕获_dispatcherSchedulerDispatcherScheduler.

您可以在此处查看ImmediateCurrentSchedulers 的说明 - http://introtorx.com/Content/v1.0.10621.0/15_SchedulingAndThreading.html#SchedulersIndepth

原始代码的替代方案可能是运行第三个线程来充当 EventLoop,使用完美命名的EventLoopScheduler

void Main()
{
    var els = new EventLoopScheduler(ts => new Thread(ts) { IsBackground = true, Name = "MyEventLoopThread"});
    els.Schedule(0, (scheduler, _)=>Run(scheduler));
}
static IDisposable Run(IScheduler mainThreadScheduler)
{
    Log("init");
    return Observable.Return(0)
        .ObserveOn(NewThreadScheduler.Default)
        .Do(_ => Log("Do1 method"))
        .ObserveOn(mainThreadScheduler)
        .Do(_ => Log("Do2 method"))
        .Subscribe(_ => Log("subscribe method"));
}
static void Log(string label)
{
    Console.WriteLine("{0} on {1}", label, Thread.CurrentThread.ManagedThreadId);
}
Run Code Online (Sandbox Code Playgroud)

这会创建以下(预期)输出

init on 28
Do1 method on 29
Do2 method on 28
subscribe method on 28
Run Code Online (Sandbox Code Playgroud)