我正在尝试编写一个接受IConnectableObservable的方法,对其进行一些处理并返回一个新的IConnectableObservable,它可以流处理已处理的数据和一些其他项。流式传输的序列是有限的,但它有副作用,所以它只需要运行一次。但是,我正在尝试用它做两件事:
以下是我做这件事的最佳尝试,但我觉得可能有一种更好的方法可以解决这个问题。
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);
答案 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
我还检查过原始的可观察值只生成一次。