我正在尝试使用RxPY将ReactiveX集成到我的GUI中。这是一个普遍的ReactiveX问题。
假设我有一个可视化,它依赖于使用rbind(a=l[["a"]], b=l[["b"]])
# x y
# a 1 2
# b 2 3
的多个Observable流。当一个Observable更改时,这很有效,例如当用户修改值时;可视化使用新值进行更新。但是,有时两个Observable都会同时更新,例如当用户从单个文件加载两个流的数据时。从技术上讲,一个Observable将在另一个之前更新(以导入函数中的第一个为准)。因此,绘图将更新两次,但是对于所有意图和目的,它只需要更新一次。
我的一些可视化计算成本很高,所以我想确保如果两个流同时更新 ,那么组合流只会发出一个值。我可以想到几个选择:
在合并流上使用combine_latest(stream1, stream2, plot_function)
小超时(如50ms)。这种做法对我来说似乎很脏。
请勿直接使用debounce()
。将两个流包装在一个也有某种combine_latest
标志的新对象中。如果我将updating
标志设置为True,那么在我将updating
标志设置为False之前不要发出任何内容。这种方法感觉有状态,它破坏了流的可组合性。
在更新所有流之前,告知所有可视化不更新。同样,这打破了封装,因为可视化不应该关心上游发生的事情。它应该只从组合流中接收新值并制作漂亮的图片。
使可视化细化得足够精细,以便首先更新一个流只会带来很小的性能损失。对于某些可视化来说,这是不可能的,例如基于点和网格大小计算网格的可视化。如果或点的网格尺寸发生变化,则需要重新计算整个网格。
Rx中是否有一些工具可以“同时”处理多个流?我觉得我要求的是魔术。
对于使用Rx制作GUI程序的任何人:除了通过流发送新值之外,还有一些更好的架构我应该用于模型吗?
如果这个问题不清楚,请在评论中告诉我,我会尝试做一个更具体的例子。
以下是Python RxPY程序示例:
updating
打印:
import rx
stream1 = rx.subjects.BehaviorSubject(1)
stream2 = rx.subjects.BehaviorSubject(2)
rx.Observable\
.combine_latest(stream1, stream2, lambda x, y: (x, y))\
.subscribe(print)
stream1.on_next(3)
stream2.on_next(4)
如何同时更新(1, 2)
(3, 2)
(3, 4)
和stream1
的值,以便结果如下?
stream2
换句话说,我怎么能以这样一种方式修改(1, 2)
(3, 4)
,我可以告诉它下游“嘿,等一下我更新其他流然后你发出你的下一个值”?
答案 0 :(得分:0)
我找到了一个可能的答案,但这不是最好的,我想要其他人。
我发现了pausable
组合子。通过传入发出True或False的流,您可以控制序列是否将被暂停。这是我的例子的修改:
import rx
stream1 = rx.subjects.BehaviorSubject(1)
stream2 = rx.subjects.BehaviorSubject(2)
pauser = rx.subjects.BehaviorSubject(True)
rx.Observable\
.combine_latest(stream1, stream2, lambda x, y: (x, y))\
.pausable(pauser)\
.subscribe(print)
# Begin updating simultaneously
pauser.on_next(False)
stream1.on_next(3)
stream2.on_next(4)
# Update done, resume combined stream
pauser.on_next(True)
# Prints:
# (1, 2)
# (3, 4)
要应用于我的GUI,我可以在我的模型中创建一个名为BehaviorSubject
的{{1}},它会发出是否正在更新整个模型。例如,如果同时更新updating
和stream1
,那么我可以将stream2
设置为True。在生成成本高昂的任何可视化上,我可以应用updating
的值来暂停组合流。
答案 1 :(得分:0)
这适用于Rx for c#:
var throttled = source.Publish(hot => hot.Buffer(() => hot.Throttle(dueTime));
这里的dueTime
值是.NET中的TimeSpan
。它只是说出你想要在它产生的值之前不活动的时间窗口。这基本上吞噬了在一段时间内“同时”产生的价值。
在这种情况下,source
将是您的.combine_latest(...)
可观察对象。