如何使NewThreadScheduler.Default计划适用于不同的线程

时间:2017-02-04 04:49:00

标签: system.reactive

试图将我的头围绕Rx,以下代码似乎不起作用,因为我希望它在不同的线程上运行。我错过了什么?

using System;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Threading;


namespace OverviewConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Thread {0}", Thread.CurrentThread.ManagedThreadId);

            var query = Enumerable.Range(1, 5).Select(n => n);

            IObservable<int> observableQuery = query.ToObservable(NewThreadScheduler.Default);
            observableQuery.Subscribe(ProcessNumber, ImDone);

        }

        static void ProcessNumber(int number)
        {
            Console.WriteLine("{0} Thread {1}", number, Thread.CurrentThread.ManagedThreadId);
        }

        static void ImDone()
        {
            Console.WriteLine("I am done!");
        }
    }
}

NewThreadScheduler.Default 安排所有在同一线程上工作。我试图在不同的线程上安排它们。

我已经看到了这个SO answer,但答案显示似乎已经过时,因为IEnumerable不再有Do方法。 有人可以帮助我如何在不同的线程上运行它们吗?

必须安装System.Reactive nuget包才能运行上述程序。

2 个答案:

答案 0 :(得分:1)

对于一个简单的问题,答案并非如此。

ToObservable实质上检查名为ScheduleLongRunning的调度程序优化是否可用 - 顾名思义,它是运行可能长时间运行的单个任务,从而阻止调度程序。否则,它必须递归地调度枚举,这是一个效率更低的命令。

这里有NewThreadScheduler,它是支持ScheduleLongRunning的理想候选者 - 它只需要在新线程上运行整个thunk。

最终结果是最终所有工作都安排在一个线程中。

最后,NewThreadScheduler对于枚举而言过于苛刻,因此您可能希望切换到TaskPoolScheduler。但是等等,同样的优化会在 one Task上运行整个事情。

所以ToObservable(TaskPoolScheduler.Default.DisableOptimizations())

P.S。

与问题无关,但Do方法以及大量有用的运算符都在System.Interactive包中。如果您不想安装整个软件包,Do只是

public static IEnumerable<T> Do<T>(this IEnumerable<T> source, Action<T> sideEffect)
{
    foreach (var value in source)
    {
        sideEffect(value);
        yield return value;
    }
}

答案 1 :(得分:1)

someEnumerable.ToObservable(scheduler)计划在该调度程序上运行observable的所有项。如果要安排每个单独的项目,则必须将每个项目转换为自己的可观察项目。以下是:

IObservable<int> observableQuery = query
    .ToObservable()
    .SelectMany(i => Observable.Return(i).ObserveOn(NewThreadScheduler.Default /*Or TaskPoolScheduler.Default as Asti mentioned */));