两者同时变化时组合Observable

时间:2015-08-19 19:40:49

标签: reactive-programming rx-java rxjs rx-py

我正在尝试使用RxPY将ReactiveX集成到我的GUI中。这是一个普遍的ReactiveX问题。

假设我有一个可视化,它依赖于使用rbind(a=l[["a"]], b=l[["b"]]) # x y # a 1 2 # b 2 3 的多个Observable流。当一个Observable更改时,这很有效,例如当用户修改值时;可视化使用新值进行更新。但是,有时两个Observable都会同时更新,例如当用户从单个文件加载两个流的数据时。从技术上讲,一个Observable将在另一个之前更新(以导入函数中的第一个为准)。因此,绘图将更新两次,但是对于所有意图和目的,它只需要更新一次。

我的一些可视化计算成本很高,所以我想确保如果两个流同时更新 ,那么组合流只会发出一个值。我可以想到几个选择:

  1. 在合并流上使用combine_latest(stream1, stream2, plot_function)小超时(如50ms)。这种做法对我来说似乎很脏。

  2. 请勿直接使用debounce()。将两个流包装在一个也有某种combine_latest标志的新对象中。如果我将updating标志设置为True,那么在我将updating标志设置为False之前不要发出任何内容。这种方法感觉有状态,它破坏了流的可组合性。

  3. 在更新所有流之前,告知所有可视化不更新。同样,这打破了封装,因为可视化不应该关心上游发生的事情。它应该只从组合流中接收新值并制作漂亮的图片。

  4. 使可视化细化得足够精细,以便首先更新一个流只会带来很小的性能损失。对于某些可视化来说,这是不可能的,例如基于点和网格大小计算网格的可视化。如果点的网格尺寸发生变化,则需要重新计算整个网格。

  5. 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) ,我可以告诉它下游“嘿,等一下我更新其他流然后你发出你的下一个值”?

2 个答案:

答案 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}},它会发出是否正在更新整个模型。例如,如果同时更新updatingstream1,那么我可以将stream2设置为True。在生成成本高昂的任何可视化上,我可以应用updating的值来暂停组合流。

答案 1 :(得分:0)

这适用于Rx for c#:

var throttled = source.Publish(hot => hot.Buffer(() => hot.Throttle(dueTime));

这里的dueTime值是.NET中的TimeSpan。它只是说出你想要在它产生的值之前不活动的时间窗口。这基本上吞噬了在一段时间内“同时”产生的价值。

在这种情况下,source将是您的.combine_latest(...)可观察对象。