我正在使用反应式编程来做一堆计算。这里是跟踪两个数和它们的和的简单示例:如何只发出一致的计算?
static void Main(string[] args) {
BehaviorSubject<int> x = new BehaviorSubject<int>(1);
BehaviorSubject<int> y = new BehaviorSubject<int>(2);
var sum = Observable.CombineLatest(x, y, (num1, num2) => num1 + num2);
Observable
.CombineLatest(x, y, sum, (xx, yy, sumsum) => new { X = xx, Y = yy, Sum = sumsum })
.Subscribe(i => Console.WriteLine($"X:{i.X} Y:{i.Y} Sum:{i.Sum}"));
x.OnNext(3);
Console.ReadLine();
}
这产生以下输出:
X:1 Y:2 Sum:3
X:3 Y:2 Sum:3
X:3 Y:2 Sum:5
通知第二输出结果如何为“不正确”,因为它表示的是3 + 2 = 3。我明白为什么会发生这种情况(x在更新之前更新),但我希望我的输出计算是原子性/一致的 - 在所有相关计算完成之前不应发射任何值。我的第一种方法是...
Observable.When(sum.And(Observable.CombineLatest(x, y)).Then((s, xy) => new { Sum = s, X = xy[0], Y = xy[1] }));
这似乎适用于我的简单示例。但我的实际代码有很多计算值,我无法弄清楚如何调整它。例如,如果有一个和平和平衡,我不知道如何在采取行动之前等待其中的每一个发射一些东西。
应该工作的一种方法(in-theory)是为所有我关心的值添加时间戳,如下所示。
Observable
.CombineLatest(x.Timestamp(), y.Timestamp(), sum.Timestamp(), (xx, yy, sumsum) => new { X = xx, Y = yy, Sum = sumsum })
.Where(i=>i.Sum.Timestamp>i.X.Timestamp && i.Sum.Timestamp>i.Y.Timestamp)
// do the calculation and subscribe
该方法适用于非常复杂的模型。我所要做的就是确保不会发出比任何核心数据值都早的计算值。我觉得这是一个混乱。它并没有在我的控制台应用程序中实际工作。当我用自定义扩展替换Timestamp时,它指定了顺序int64,它确实有效。
什么是简单,干净的方式来处理这种事情?
=======
我在这里取得了一些进展。在等待触发计算的数据值之前,等待sum和sumSquared发出一个值。
var all = Observable.When(sum.And(sumSquared).And(Observable.CombineLatest(x, y)).Then((s, q, data)
=> new { Sum = s, SumSquared = q, X = data[0], Y = data[1] }));
这很简单。我仍然对这些方法感到困扰。当我创建它们并针对这些依赖性定制我的查询时,它们要求我定义可观察对象之间的依赖关系。在Excel中,您只需更改一个单元格,所有内容都会更新;没有中间的无效信息看。我希望有一种方法可以做到这一点,比如Observable.CombineLatest(bool waitForSynchronousUpdatesToComplete)。 – JustinM
假设IObservable代表电子邮件地址,IObservable 指示电子邮件地址是否格式正确。如果你想同时显示两条信息,你不应该等待DistinctUntilChanged,因为验证结果可能没有改变。在这种情况下,也许最好是使用Zip关联输入和匹配输出,并发出重复的验证消息。再次 - 使用IObservable的东西需要太多关于如何定义函数的知识。应该有更好的方式来使它像Excel一样工作。 –
JustinM
您目前的设置是并行流,这有很多优点,但这意味着流之间没有排序。 –