观察回到当前线程

时间:2016-06-16 19:04:35

标签: c# concurrency system.reactive

我正在尝试在新线程上安排一个observable并将结果返回到当前线程。

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);
        }
    }
}

这是我得到的结果:

init on 9
Do1 method on 10
Do2 method on 10
subscribe method on 10

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

init on 9
Do1 method on 10
Do2 method on 9
subscribe method on 9

1 个答案:

答案 0 :(得分:3)

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

如果您在GUI应用程序中执行此操作,则主线程将是某种EventLoop,即WPF / Silverlight中的Dispatcher。 现在很容易将控制返回到主线程" - ObserveOn(_dispatcherScheduler)其中_dispatcherSchedulerDispatcherScheduler的捕获实例。

您可以在此处查看ImmediateCurrent计划程序的解释 - http://introtorx.com/Content/v1.0.10621.0/15_SchedulingAndThreading.html#SchedulersIndepth

原始代码的替代方法可能是使用完美命名的EventLoopScheduler

运行第三个线程作为EventLoop
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);
}

创建以下(预期)输出

init on 28
Do1 method on 29
Do2 method on 28
subscribe method on 28