我想知道如何将一个observable变换为类似于switchMap,而不是限制为单个活动流有多个(有限的)流。
目的是让多个任务同时工作到某些任务计数限制,并允许新任务以FIFO队列策略启动,这意味着任何新任务到达将立即开始,队列中最旧的任务将被取消。
switchMap将为源的每次发射创建Observable,并且一旦创建新的一个流就会取消先前运行的Observable流,我想实现类似但允许某种程度的并发(如flatMap),这意味着允许创建多个Observable对于每个发射,并且同时运行到某个并发限制,当达到并发限制时,最旧的observable将被取消,新的observable将启动。
实际上,这也与使用maxConcurrent的flatMap类似,但是当达到maxConcurrent时,不是在队列中等待新的Observable,而是取消旧的Observable并立即输入新的Observable。
答案 0 :(得分:3)
你可以试试这个变压器:
public static <T, R> Observable.Transformer<T, R> switchFlatMap(
int n, Func1<T, Observable<R>> mapper) {
return f ->
Observable.defer(() -> {
final AtomicInteger ingress = new AtomicInteger();
final Subject<Integer, Integer> cancel =
PublishSubject.<Integer>create().toSerialized();
return f.flatMap(v -> {
int id = ingress.getAndIncrement();
Observable<R> o = mapper.call(v)
.takeUntil(cancel.filter(e -> e == id + n));
cancel.onNext(id);
return o;
});
})
;
}
示威:
public static void main(String[] args) {
PublishSubject<Integer> ps = PublishSubject.create();
@SuppressWarnings("unchecked")
PublishSubject<Integer>[] pss = new PublishSubject[3];
for (int i = 0; i < pss.length; i++) {
pss[i] = PublishSubject.create();
}
AssertableSubscriber<Integer> ts = ps
.compose(switchFlatMap(2, v -> pss[v]))
.test();
ps.onNext(0);
ps.onNext(1);
pss[0].onNext(1);
pss[0].onNext(2);
pss[0].onNext(3);
pss[1].onNext(10);
pss[1].onNext(11);
pss[1].onNext(12);
ps.onNext(2);
pss[0].onNext(4);
pss[2].onNext(20);
pss[2].onNext(21);
pss[2].onNext(22);
pss[1].onCompleted();
pss[2].onCompleted();
ps.onCompleted();
ts.assertResult(1, 2, 3, 10, 11, 12, 20, 21, 22);
}
答案 1 :(得分:0)
虽然现成的解决方案不可用,但下面的内容应该有所帮助。
public static void main(String[] args) {
Observable.create(subscriber -> {
for (int i = 0; i < 5; i++) {
Observable.timer(i, TimeUnit.SECONDS).toBlocking().subscribe();
subscriber.onNext(i);
}
})
.switchMap(
n -> {
System.out.println("Main task emitted event - " + n);
return Observable.interval(1, TimeUnit.SECONDS).take((int) n * 3)
.doOnUnsubscribe(() -> System.out.println("Unsubscribed for main task event - "+ n));
}).subscribe(n2 -> System.out.println("\t" + n2));
Observable.timer(20, TimeUnit.SECONDS).toBlocking().subscribe();
}
Observable.create
部分创建一个缓慢的生成器,以发出0的方式发出项目,睡眠1秒并发出1,睡眠2秒,发出2等等。
switchMap
为每个元素创建Observable
个对象,每秒发出一次数字。您还可以注意到,每次主Observable
发出元素时以及取消订阅时,它都会打印一行。
因此,在您的情况下,您可能有兴趣使用doOnUnsubscribe
关闭最早的任务。希望它有所帮助。
伪代码下面可能有助于更好地理解。
getTaskObservable()
.switchMap(
task -> {
System.out.println("Main task emitted event - " + task);
return Observable.create(subscriber -> {
initiateTaskAndNotify(task, subscriber);
}).doOnUnsubscribe(() -> checkAndKillIfMaxConcurrentTasksReached(task));
}).subscribe(value -> System.out.println("Done with task and got output" + value));