Concurrency 将流拆分,然后与RX组合

Concurrency 将流拆分,然后与RX组合,concurrency,rxjs,rx-java,rx-java2,system.reactive,Concurrency,Rxjs,Rx Java,Rx Java2,System.reactive,我正在寻找某种最佳实践或模式来处理以下情况: 我有两个流,我想以以下方式组合: |-------------| | Transform A |------------>|---------| |---------|----->|-------------| | | Stream A-----&g

我正在寻找某种最佳实践或模式来处理以下情况:

我有两个流,我想以以下方式组合:

                               |-------------|
                               | Transform A |------------>|---------|
              |---------|----->|-------------|             |         |
Stream A----->| Split A |                                  | Combine |-------> ?
              |---------|----->|--------------------|      |   All   |
                               | Transform and      |      |         |
                               | Combine A (latest) |----->|---------|
                               | and B (latest)     |
Stream B---------------------->|--------------------|
流A和B正在异步生成事件。我想把A和B的最新结果结合起来,把结果和A上面的计算结果结合起来

当接收到B中的事件时,整个管道将使用来自此事件的值和来自A的最新值运行


是否有一种优雅的方法来确保当接收到A中的事件时,将所有运行的与来自A的基于此事件的事件相结合,并避免转换A转换并使用
Observable.Publish组合A和B

之间的竞争条件(来源,x=>)
确保您只有一个订阅
源代码
,但您可以将其作为变量
x
任意多次使用。它确保您永远不会在
源代码上获得任何竞争条件

您可以这样使用它:

Func<A, C> transform_A = a => ...;
Func<A, B, D> combine_A_and_B = (a, b) => ...;
Func<C, D, E> combine_all = (c, d) => ...;

IObservable<A> stream_a = ...;
IObservable<B> stream_b = ...;

IObservable<E> query =
    stream_a
        .Publish(stream_a_published =>
        {
            var stream_c = stream_a_published.Select(transform_A);
            var stream_d = stream_a_published.CombineLatest(stream_b, combine_A_and_B);
            return stream_c.CombineLatest(stream_d, combine_all);
        });
Func变换_A=A=>。。。;
Func combine_A_和_B=(A,B)=>。。。;
Func combine_all=(c,d)=>。。。;
可观测流_a=。。。;
可观测流_b=。。。;
可观测查询=
溪流
.Publish(stream\u a\u published=>
{
var stream_c=stream_a_published.选择(transform_a);
var stream_d=stream_a_published.CombineTest(stream_b,combine_a_and_b);
返回流c.CombineTest(流d,合并所有);
});

您可以通过将单线程调度程序与debounce操作符相结合来实现这一点:

class ManualExecutor : Executor {
    private val tasks = ArrayDeque<Runnable>()

    override fun execute(command: Runnable) = tasks.push(command)

    fun runAllTasks() {
        while (tasks.isNotEmpty()) {
            tasks.pop().run()
        }
    }
}

val a: Observable<A>
val b: Observable<B>

val scheduler = Schedulers.from(ManualExecutor())

val aTransformed = a.observeOn(scheduler).map { transformA(it) }
val aCombinedWithB = combine(a, b).observeOn(scheduler)

val final = combine(aTransformed, aCombinedWithB).debounce(0)

// some time later....
emitA() // now all the updates are queued in our ManualExecutor
scheduler.runAllTasks() // final will only emit once, not twice!

根据@tonicsoft的最新评论,我们的想法是:

Flowable streamPairA=可流动。间隔(3秒)
.doOnNext(l->System.out.println(“A的新值:“+l))
.map(l->新对(l,“Hello”+l));
可流动流量B=可流动。间隔(5秒)
.doOnNext(l->System.out.println(“B:+l的新值”);
可流动的组合测试(streamPairA,streamB,(x,y)->“-->”+x.value()
+“(最新的A:“+x.key()+”,最新的B:“+y+”)
.subscribe(System.out::println);
Flowable.timer(1,分钟)//只是暂时阻塞主线程
.阻止订阅();

这实际上取决于当只有
A
或只有
B
发出时,您想要什么行为。否则,
withLatestFrom
CombineTest
应该是您要查找的。当只有B到达时,我希望与A的最新版本合并。当只有A到达时,我希望B的最新版本与A的当前版本合并,但我需要避免竞争条件,导致将A的当前值与基于A的先前值的计算相结合。是的,但是如果
B
到达并且还没有
A
呢?在这种情况下,我同意的标准行为是使用最新的from。我不太关心这个问题,而更关心的是在两个派生流中获得相同版本的A的问题,这两个派生流基于将图片保存为图形,我猜您的问题是其中有一个菱形,您试图避免在菱形的叶节点处获得双重更新。用现成的rx很难做到这一点。您可以操纵调度器和解Bounce来获得这种行为。我已经开始用一个图书馆来做这个实验:它还没有真正准备好被消费,但它可能会给你一些想法。
              |-----------------------|
Stream A----->| map A to              |
              | pair(A, transform(A)) |                 
              |-----------------------|                 
                        |                               
                        |----->|--------------------|   
                               | Combine A, t(A)    |   
                               | and B (latest)     |--> ?
                               | into 3-tuple       |
Stream B---------------------->|--------------------|