繁体   English   中英

Rx如何并行化长时间运行的任务?

[英]Rx How to parallelize long-running task?

我有以下摘录一些xml元素的片段(从svn log --xml ...进程的输出中读取),然后为每个xml元素运行一个长时间运行的方法。

var proc = Process.Start(svnProcInfo);
var xml = XDocument.Load(proc.StandardOutput);

var xElements = xml.Descendants("path")
                   .ToObservable()
                   //.SubscribeOn(ThreadPoolScheduler.Instance) 
                   .Select(descendant => return LongRunning(descendant));
xElements
    //.SubscribeOn(NewThreadScheduler.Default)
    .Subscribe(result => Console.WriteLine(result);

Console.ReadKey();

LongRunning方法并不重要,但是我在其中记录了运行它的线程。 假设它运行一秒钟。

我的问题是,取消注释任何SubscribeOn()行都没有任何效果。 LongRunning的调用是连续的, LongRunning发生一次,在同一线程上(尽管与主(初始)线程不同)。

这是一个控制台应用程序。

我是Rx的新手。 我想念什么?

编辑:

在尝试了李·坎贝尔的答案后,我注意到了另一个问题。

Console.Error.WriteLine("Main thread " + Thread.CurrentThread.ManagedThreadId);

var xElements = xml.Descendants("path").ToObservable()
    //.ObserveOn(Scheduler.CurrentThread)
    .SelectMany(descendant =>     
          Observable.Start(()=>LongRunning(descendant),NewThreadScheduler.Default))
    .Subscribe(result => Console.WriteLine(
         "Result on: " + Thread.CurrentThread.ManagedThreadId));

[...]

string LongRunning(XElement el)
{
    Console.WriteLine("Execute on: Thread " + Thread.CurrentThread.ManagedThreadId);
    DoWork();
    Console.WriteLine("Finished on Thread " + Thread.CurrentThread.ManagedThreadId);
    return "something";
}

这给出以下输出:

Main thread 1
Execute on: Thread 3
Execute on: Thread 4
Execute on: Thread 5
Execute on: Thread 6
Execute on: Thread 7
Finished on Thread 5
Finished on Thread 6
Result on: 5
Result on: 6
Finished on Thread 7
Result on: 7
Finished on Thread 3
Result on: 3
Finished on Thread 4
Result on: 4
Done! Press any key...

我需要的是一种将结果“排队”到同一线程的方法。 我以为这就是ObserveOn()的作用,但是取消注释上面的ObserveOn()行不会改变结果。

首先,Rx是用于控制异步(特别是可观察序列)的库(或范例)。 您这里拥有的是一个可枚举的序列(Xml后代)和一个阻塞/同步的LongRunning方法调用。

通过在可枚举序列上调用ToObservable() ,您实际上仅遵从该接口,但是随着序列的实现(渴望而不是懒惰),实际上没有什么可观察/异步的。

通过调用SubscribeOn ,您有一个正确的想法,但是转换已在ToObservable()运算符中完成。 您可能打算调用ToObservable(ThreadPoolScheduler.Instance)以便IEnumerable任何慢速迭代都可以在另一个线程上完成。 但是...我认为这不会是一个缓慢的迭代器,因此这可能无法解决任何问题。

您最可能想做的事情(如果Rx是解决此类问题的最佳工具,这是可疑的)是安排对LongRunning方法的调用。 但是,这意味着您需要将Asyncrony添加到您的选择中。 一种很好的方法是使用Rx Factory方法之一,例如Observable.FromAsyncObservable.Start 但是,这会使您的序列成为IObservable<IObservable<T>> 您可以使用SelectManyMerge对其进行展平。

说了这么多,我想你要做的是:

var proc = Process.Start(avnProcInfo);
var xml = XDocument.Load(proc.StandardOutput);

//EDIT: Added ELS to serialise results onto a single thread.
var els = new EventLoopScheduler(threadStart=>new Thread(threadStart)
    {
        IsBackground=true, 
        Name="MyEventLoopSchedulerThread"
    });

var xElements = xml.Descendants("path").ToObservable()
                .SelectMany(descendant => Observable.Start(()=>LongRunning(descendant),ThreadPoolScheduler.Instance))
                .ObserveOn(els)
                .Subscribe(result => Console.WriteLine(result));

Console.ReadKey();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM