在函数响应式编程的上下文中,“故障”的定义是什么?
我知道在某些 FRP 框架中可能会出现“故障”,而在其他框架中则不会。例如,RX 不是无故障的,而 ReactFX 是无故障的 [ 1 ]。
有人可以举一个非常简单的例子来说明使用 RX 时故障是如何以及何时发生的,并在同一个例子中展示相应的 ReactFX 解决方案如何以及为什么没有故障。
谢谢阅读。
在函数响应式编程的上下文中,“故障”的定义是什么?
我知道在某些 FRP 框架中可能会出现“故障”,而在其他框架中则不会。例如,RX 不是无故障的,而 ReactFX 是无故障的 [ 1 ]。
有人可以举一个非常简单的例子来说明使用 RX 时故障是如何以及何时发生的,并在同一个例子中展示相应的 ReactFX 解决方案如何以及为什么没有故障。
谢谢阅读。
我(自己)最喜欢的定义:
故障是可观察状态中的暂时不一致。
来自Scala.Rx的定义:
在 FRP 的上下文中,故障是数据流图中的临时不一致。由于更新不会立即发生,而是需要时间来计算,因此 FRP 系统中的值可能会在更新过程中暂时不同步。此外,根据 FRP 系统的性质,可以在传播中多次更新节点。
考虑整数变量a
, b
。定义sum
等prod
,。
sum := a + b
_
prod := a * b
让我们将此示例重写为 JavaFX:
IntegerProperty a = new SimpleIntegerProperty();
IntegerProperty b = new SimpleIntegerProperty();
NumberBinding sum = a.add(b);
NumberBinding prod = a.multiply(b);
现在让我们写一点一致性检查:
InvalidationListener consistencyCheck = obs -> {
assert sum.intValue() == a.get() + b.get();
assert prod.intValue() == a.get() * b.get();
};
sum.addListener(consistencyCheck);
prod.addListener(consistencyCheck);
a.set(1);
b.set(2);
此代码失败,最后一行出现断言错误,因为:
b
已更新(至 2)
sum
已更新(至 3)
这是一个小故障——prod
暂时与a
and不一致b
。
首先请注意,ReactFX并不是开箱即用的“无故障”,但它为您提供了消除故障的工具。除非您有意识地使用它们,否则 ReactFX 并不比 RX(例如 rxJava)更无故障。
在 ReactFX 中消除故障的技术依赖于事件传播是同步的这一事实。另一方面,RX 中的事件传播始终是异步的,因此这些技术无法在 RX 系统中实现。
在上面的示例中,我们希望将侦听器通知推迟到两者sum
都prod
更新后。这是使用 ReactFX 实现此目的的方法:
import org.reactfx.Guardian;
import org.reactfx.inhibeans.binding.Binding;
IntegerProperty a = new SimpleIntegerProperty();
IntegerProperty b = new SimpleIntegerProperty();
Binding<Number> sum = Binding.wrap(a.add(b)); // Binding imported from ReactFX
Binding<Number> prod = Binding.wrap(a.multiply(b)); // Binding imported from ReactFX
InvalidationListener consistencyCheck = obs -> {
assert sum.getValue().intValue() == a.get() + b.get();
assert prod.getValue().intValue() == a.get() * b.get();
};
sum.addListener(consistencyCheck);
prod.addListener(consistencyCheck);
// defer sum and prod listeners until the end of the block
Guardian.combine(sum, prod).guardWhile(() -> {
a.set(1);
b.set(2);
});
简短回答:故障 = 不一致/非法/无意义的状态。
另外,请参阅 Sodium 作者谈话的第 29 分钟以获得另一个答案:http: //youtu.be/gaG3tIb3Lbk。
以及相关的 SOF 答案:如何避免 Rx 中的故障
因此,这是我根据 Tomas 的回答对故障的理解。
有一个数据流图,有 3 个节点:A、B、C
A->B
A->C
在这个简单的示例中,如果我更改 A 并导致更改 B 但 C 尚未更新,则会发生故障。这是一个故障。
C 与 B 不一致。
假设 B=2*A,C=2*A。
然后,如果 B 不等于 C,那么这是一个故障。
这是 C# RX 中致命“故障”情况的一个非常简短的理论示例
var t = Observable
.Interval(TimeSpan.FromSeconds(1))
.Publish()
.RefCount();
var s = t.CombineLatest(t, (t1,t2) => 1/(1-(t1-t2));
由于t1
和t2
都代表热观测值的最新值t
,人们会假设t1-t2
它总是如此0
。所以 s 应该永远是1
。
但是当订阅 s 时,我们确实得到1
了第一个观察值,但随后我们得到了除以零的异常。在 RxJS 中,我们会得到NaN
.
原因很简单:当其中一个或产生一个值a.CombineLatest(b, f)
时会做出反应,将这个新值与另一个可观察到的最后观察到的值结合起来。这是设计使然,但根据我的经验,使用 RX 的人有时会认为这些是故障,尤其是来自其他具有不同“最新”概念的 FRP 库时。a
b
这当然是一个人为的例子,只是为了说明对CombineLatest
.
也许CombineLatest
应该WhenAny
像在ReactiveUI
库中那样调用,这会澄清操作语义?