Combining Observables when both change simultaneously

左心房为你撑大大i 提交于 2019-12-08 05:44:32

问题


I am trying to integrate ReactiveX into my GUI using RxPY. This is a general ReactiveX question.

Say I have a visualization that depends on multiple Observable streams using combine_latest(stream1, stream2, plot_function). This works great when one Observable changes, like when the user modifies a value; the visualization updates using the new values. However, sometimes both Observables are updated simultaneously, like when the user loads data for both streams from a single file. Technically, one Observable will be updated before the other (whichever comes first in the import function). As a result, the plot will be updated twice, but for all intents and purposes it need only be updated once.

Some of the visualizations I have are expensive to compute, so I want to make sure that if both streams are updated simultaneously, then the combined stream only emits one value. I can think of a few options:

  1. Use debounce() with a small timeout (like 50ms) on the combined stream. This approach seems dirty to me.

  2. Don't use combine_latest directly. Wrap the two streams in a new object that also has some sort of updating flag. If I set the updating flag to True, then don't emit anything until I set the updating flag to False. This approach feels to stateful, and it ruins the composability of the streams.

  3. Tell all visualizations not to update until all the streams are updated. Again, this breaks encapsulation because the visualization shouldn't care what is happening upstream. It should just receive the new values from the combined stream and make a pretty picture.

  4. Make the visualizations fine-grained enough that one stream updating first only introduces a small performance penalty. This is impossible for some visualizations, like a visualization that computes a mesh based on points and a mesh size. If the points or the mesh size changes, then the whole mesh needs to be recomputed.

Is there some facility in Rx to handle "simultaneously" updating multiple streams? I feel like what I'm asking for is magic.

For anyone who has made GUI programs using Rx: is there some better architecture I should be using for models besides sending new values through streams?

If this question is unclear, please tell me in a comment and I will try to make a more concrete example.

Example

Here is a sample Python RxPY program:

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)

This prints:

(1, 2)
(3, 2)
(3, 4)

How could I update the values of stream1 and stream2 simultaneously so that the following becomes the result?

(1, 2)
(3, 4)

In other words, how could I modify combine_latest in such a way that I can tell it downstream "hey, wait a second while I update the other streams before you emit your next value"?


回答1:


I have found one possible answer, but it is not the best and I would like others.

I discovered the pausable combinator. By passing in a stream that emits True or False, you can control if a sequence will be paused. Here is a modification of my example:

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)

To apply to my GUI, I can create a BehaviorSubject called updating in my model that emits whether or not the whole model is being updated. For example, if stream1 and stream2 are being simultaneously updated, then I can set updating to True. On any visualizations that are expensive to produce, I can apply the value of updating to pause the combined stream.




回答2:


This works in Rx for c#:

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

The dueTime value here is a TimeSpan in .NET. It merely says what the window of time is that you want to have inactivity before a value it produced. This basically gobbles up values produced "simultaneously" within a margin of time.

The source in this case would be your .combine_latest(...) observable.



来源:https://stackoverflow.com/questions/32104268/combining-observables-when-both-change-simultaneously

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!