处理后流式传输IConnectableObservable

时间:2015-10-07 04:44:08

标签: c# c#-4.0 system.reactive reactive-programming

我正在尝试编写一个接受IConnectableObservable的方法,对其进行一些处理并返回一个新的IConnectableObservable,它可以流处理已处理的数据和一些其他项。流式传输的序列是有限的,但它有副作用,所以它只需要运行一次。但是,我正在尝试用它做两件事:

  1. 使用选择查询转换流中的每个元素。
  2. 将流中的每个元素收集到一个数组中,然后对数组进行一些处理并对结果进行流处理。
  3. 以下是我做这件事的最佳尝试,但我觉得可能有一种更好的方法可以解决这个问题。

    protected override IConnectableObservable<ITestResult<ITestOutput<double, double>, ITestLimit<double>>> ProcessOutput(
        IConnectableObservable<ITestOutput<double, double>> output, InputVerificationTestCase testCase)
    {
        var obsResults = output.Select(o =>
        {
            var limits = GenerateDcAccuracyLimits.CalculateAbsoluteLimits(o.Input, testCase.FullScaleRange, testCase.Limits);
            return new TestResult<ITestOutput<double, double>, ITestLimit<double>>
            {
                Component = "Variable Gain Module Input",
                Description = "Measurement Accuracy",
                Limits = limits,
                Output = o,
                Passed = _validationService.Validate(o.Result, limits)
            };
        });
    
        var observable = Observable.Create<ITestResult<ITestOutput<double, double>, ITestLimit<double>>>(obs =>
        {
            var resultTask = obsResults.ForEachAsync(obs.OnNext);
            var fitTask = output.ToArray().ForEachAsync(arr =>
            {
                resultTask.Wait();
                var fit = ComputeErrorFit(arr, testCase);
                obs.OnNext(GetGainErrorResult(fit.Item2, testCase));
            });
            output.Connect();
            Task.WaitAll(resultTask, fitTask);
            obs.OnCompleted();
            return Disposable.Empty;
        });
    
        return observable.Publish();
    }
    

    2015年10月7日编辑:

    以下是代码的其余部分:

    private ITestResult<ITestOutput<double, double>, ITestLimit<double>> GetGainErrorResult(double gainError, InputVerificationTestCase testCase)
    {
        var gainErrorLimit = GenerateDcAccuracyLimits.CalculateGainErrorLimits(testCase.FullScaleRange, testCase.Limits);
        return new TestResult<ITestOutput<double, double>, ITestLimit<double>>
        {
            Component = "Variable Gain Module Input",
            Description = "Gain Error",
            Passed = _validationService.Validate(gainError, gainErrorLimit),
            Output = new TestOutput<double, double> { Input = 0, Result = gainError },
            Limits = gainErrorLimit
        };
    }
    
    private Tuple<double, double> ComputeErrorFit(ITestOutput<double, double>[] outputs, InputChannelTestCase testCase)
    {
        var input = outputs.Select(o => o.Input);
        var vErr = outputs.Select(o => o.Result - o.Input);
        return Fit.Line(input.ToArray(), vErr.ToArray());
    }
    

    同样在抽象基类中,我有以下内容:

    public IConnectableObservable<TOutput> RunSingleChannel(TCase testCase)
    {
        dut.Acquisition.SampleRate.Value = SampleRate;
        dut.AnalogChannels[testCase.Channel].InputRange.Value = testCase.FullScaleRange;
        var testOutput = CreateTestProcedure(testCase.Channel).RunAsync(testCase.InputVoltages);
        return ProcessOutput(testOutput.Replay(), testCase);
    }
    
    protected abstract IConnectableObservable<TOutput> ProcessOutput(IConnectableObservable<ITestOutput<double, TAcq>> output, TCase testCase);
    

1 个答案:

答案 0 :(得分:3)

看来你正在努力用Rx做事。您确实需要避免在使用Observables的任务中混音。它们使您的代码难以推理并经常导致死锁和其他并发问题。

你应该尝试这样的事情:

protected override IConnectableObservable<ITestResult<ITestOutput<double, double>, ITestLimit<double>>> ProcessOutput(
    IConnectableObservable<ITestOutput<double, double>> output, InputVerificationTestCase testCase)
{
    var source = output.RefCount();
    return
        source
            .Select(o =>
            {
                var limits = GenerateDcAccuracyLimits.CalculateAbsoluteLimits(o.Input, testCase.FullScaleRange, testCase.Limits);
                return new TestResult<ITestOutput<double, double>, ITestLimit<double>>
                {
                    Component = "Variable Gain Module Input",
                    Description = "Measurement Accuracy",
                    Limits = limits,
                    Output = o,
                    Passed = _validationService.Validate(o.Result, limits)
                };
            })
            .Merge(
                source
                    .ToArray()
                    .Select(arr => GetGainErrorResult(ComputeErrorFit(arr, testCase).Item2, testCase)))
            .Publish();
}

你使用可连接的可观察量有点奇怪,但上面应该大致做你需要的。

我使用此示例测试了代码:

public IConnectableObservable<int> ProcessOutput(IConnectableObservable<int> output)
{
    var source = output.RefCount();
    return
        source
            .Merge(source.ToArray().Select(arr => arr.Sum()))
            .Publish();
}

void Main()
{
    var output = Observable.Range(1, 10).Publish();

    var processed = ProcessOutput(output);

    processed.Subscribe(x => Console.WriteLine(x));

    processed.Connect();
}

哪个输出:

1
2
3
4
5
6
7
8
9
10
55

我还检查过原始的可观察值只生成一次。