计算进度逻辑应该驻留在服务层上吗?

时间:2015-08-03 20:53:14

标签: c# task-parallel-library system.reactive

在我的WPF应用程序中,我的ViewModel与ViewModelService进行通信,ViewModelService又会说出一个CalculationService来检索要在View中显示的已处理数据。我希望视图能够向用户报告完成百分比。我的问题有两个。

首先是这个逻辑应该在哪里? CalculationService是否应该负责报告进度以及实际结果,或者ViewModel服务是否计算进度百分比详细信息。

其次,我看到我可以使用TPL或使用ReactiveExtentions实现此目的。在我的情况下,我倾向于反应性扩展,计算服务的API和实现看起来像这样

//This is pseudo code, just aiming to show my intention here
    IEnumerable<Output> Calculate(IEnumerable<Inputs> inputs){
             List<Output> output = new List<Output>();
             foreach(var input : inputs){
               //long running calculation, which produces output
               //outputs.Add(output)
             }
           }

假设如果我沿着Reactive路线走下去,我可以使用Reactive的OnNext来传输“Output”,当它们到达时我也可以使用Parallel.Foreach来获得性能。

有关此的任何想法或想法吗?

由于 凯

1 个答案:

答案 0 :(得分:1)

我认为视图模型层可以计算进度。

以下是我将如何使用Rx:

首先创建一个Progress<T>类,将Output提升为可以报告自己进度的类型。

public class Progress<T>
{
    public Progress(T value, int current, int total)
    {
        this.Value = value;
        this.Current = current;
        this.Total = total;
    }
    public T Value { get; private set; }
    public int Current { get; private set; }
    public int Total { get; private set; }
    public double Percentage
    {
        get
        {
            return (double)this.Current / (double)this.Total;
        }
    }
}

现在你只需要Calculate方法。

public IObservable<Progress<Output>> Calculate(IEnumerable<Inputs> inputs)
{
    return
        Observable
            .Create<Progress<Output>>(o =>
            {
                var source = inputs.ToArray();
                var total = source.Length;
                return
                    source
                        .ToObservable()
                        .Select((x, n) =>
                            new Progress<Output>(LongRunningCalculation(x), n, total))
                        .Subscribe(o);
            });     
}

这不会带来任何性能提升,但我当然不会使用Parallel.ForEach来获得任何改进。混合任务,枚举和可观察性并不是最好的。坚持一种范式总是更好。

以下是我将如何并行运行。

IObservable<Progress<Output>> Calculate(IEnumerable<Inputs> inputs)
{
    return
        Observable
            .Create<Progress<Output>>(o =>
            {
                var source = inputs.ToArray();
                var total = source.Length;
                return
                    source
                        .ToObservable()
                        .SelectMany(x => Observable.Start(() => LongRunningCalculation(x)))
                        .Select((x, n) => new Progress<Output>(x, n, total))
                        .Subscribe(o);
            });     
}