从多个任务

时间:2015-09-06 09:50:51

标签: system.reactive rx-java

我想创建一个接受S并返回Observable<T>的方法,该方法在三个(异步)任务完成后以一个值完成。

这三个任务都在队列上运行,并且他们自己的消费者在不同的线程中。

这就是我的想法:

  • 任务1通过队列接收<S, Subject<T>>并计算S的值,并使用Subject<T>onNext中设置,然后调用onComplete()。< / LI>
  • 任务2和3收到<S, Subject<Void>>并在完成工作后致电onComplete()

任务1,2和3可以独立运行,并以随机顺序完成。

现在我有三个主题,一个T和两个Void。我想返回第一个,但只有在所有任务完成后才让它发出值T。这是因为我不希望observable的任何订阅者在完成所有任务之前对T做任何事情。

组合主题以实现此行为的正确方法是什么?我可以使用CountDownLatch等轻松地将它们混在一起,但我希望有一种rx-native方式来解决这个问题。

我的计划是通过队列正确的方法使用Subjects作为回调吗?我过去常常使用CompletableFuture<T>,但我想迁移到RX。

3 个答案:

答案 0 :(得分:2)

我不完全确定主题在哪里发挥,但您可以使用When + And + Then

同步这三项任务
public IObservable<T> MyMethod<S, T>(S incoming) {

  //Create a new plan
  return Observable.When(

   //Start with Task one which will return an T from an S
   Observable.FromAsync(async () => await SomeTaskToTurnSIntoT(incoming))

   //Add in Task two which returns a System.Reactive.Unit
   .And(Observable.FromAsync(() => /*Do Task 2*/))

   //Same for Task 3
   .And(Observable.FromAsync(() => /*Do Task 3*/))

   //Only emit the item from the first Task.
   .Then((ret, _, __) => ret))

   //Finally we only want this to process once, then we will reuse the
   //existing value for subsequent subscribers
   .PublishLast().RefCount();
}

上述内容将等到所有三个项目完成后再发出。需要注意的一点是,在Rx中Void对象实际上是System.Reactive.Unit,所以如果没有值,你应该返回它。

答案 1 :(得分:2)

请勿使用Subject s。而是使用异步调度程序合并observable。所以你有:

T task1(S s);
void task2(S s);
void task3(S s);

然后

<S,T> Observable<T> get(S s) {
    return Observable.merge(
        Observable.just(s)
            .map(x -> task1(x))
            .subscribeOn(Schedulers.computation()),
        (Observable<T>) Observable.just(s)
            .doOnNext(x -> task2(x))
            .ignoreElements()
            .cast(Object.class)
            .subscribeOn(Schedulers.computation()),
        (Observable<T>) Observable.just(s)
            .doOnNext(x -> task3(x))
            .ignoreElements()
            .cast(Object.class)
            .subscribeOn(Schedulers.computation()))
        // wait for completion before emitting the single value
        .last();
}   

答案 2 :(得分:0)

您可以编写自己的Subject来为您执行此操作,但由于多种原因通常会气馁。相反,您也可以连接由您的任务生成的三个Observables / Subjects。此操作生成Observable,它会发出由这些任务生成的所有值,并且仅在所有输入Observable都已完成时才会完成。

由于它们的类型略有不同,您需要使用map()更改后两个任务生成的Observable的签名。

Observable<T> output = Observable.concat(t1, 
    t2.map(in -> null).ignoreElements(), 
    t3.map(in -> null).ignoreElements());

如果您想等待所有订阅者使用生成的值,直到所有Observable都已完成,您可以在此last()上调用Observable方法。

Observable<T> output = Observable.concat(t1, 
    t2.map(in -> null).ignoreElements(), 
    t3.map(in -> null).ignoreElements()).last();