[英]RxJava concurrency with multiple subscribers and events
我正在尋找一種方法將多個訂閱者附加到RxJava Observable流,每個訂閱者異步處理發出的事件。
我首先嘗試使用.flatMap(),但這似乎不適用於任何后續訂閱者。 所有訂閱者都在同一個線程上處理事件。
.flatMap(s -> Observable.just(s).subscribeOn(Schedulers.newThread()))
最終工作的是通過每次創建一個新的Observable來消耗新線程中的每個事件:
Observable.from(Arrays.asList(new String[]{"1", "2", "3"}))
.subscribe(j -> {
Observable.just(j)
.subscribeOn(Schedulers.newThread())
.subscribe(i -> {
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("s1=>" + Thread.currentThread().getName() + "=>" + i);
});
});
輸出:
s1=>RxNewThreadScheduler-1=>1
s1=>RxNewThreadScheduler-2=>2
s1=>RxNewThreadScheduler-3=>3
最終結果是多個訂閱者:
ConnectableObservable<String> e = Observable.from(Arrays.asList(new String[]{"1", "2", "3"}))
.publish();
e.subscribe(j -> {
Observable.just(j)
.subscribeOn(Schedulers.newThread())
.subscribe(i -> {
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("s1=>" + Thread.currentThread().getName() + "=>" + i);
});
});
e.subscribe(j -> {
Observable.just(j)
.subscribeOn(Schedulers.newThread())
.subscribe(i -> {
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("s2=>" + Thread.currentThread().getName() + "=>" + i);
});
});
e.connect();
輸出:
s2=>RxNewThreadScheduler-4=>2
s1=>RxNewThreadScheduler-1=>1
s1=>RxNewThreadScheduler-3=>2
s2=>RxNewThreadScheduler-6=>3
s2=>RxNewThreadScheduler-2=>1
s1=>RxNewThreadScheduler-5=>3
然而,這看起來有點笨重。 有更優雅的解決方案還是RxJava不是一個很好的用例呢?
使用.flatMap(s -> Observable.just(s).observeOn(Schedulers.newThread())....)
如果我正確地理解了rx-contract,那么你正試圖做一些事情,這是違背它的。
讓我們來看看合同
RxJava Observable的契約是事件(onNext(),onCompleted(),onEr ror())永遠不會同時發出。 換句話說,單個Observable流必須始終序列化並且是線程安全的。 只要排放不是並發的,每個事件都可以從不同的線程發出。 這意味着沒有 onNext()的交叉或同時執行 。 如果仍然在一個線程上執行onNext(),則另一個線程無法再次開始調用它(交錯)。 --Tomasz Nurkiewicz在RxJava的反應式編程中
在我看來,你試圖通過在外部訂閱中使用嵌套訂閱來破解合同。 對訂戶的onNext調用不再被序列化。
為什么不將“async”-workload從訂閱者移動到flatMap-operator並訂閱新的observable:
ConnectableObservable<String> stringObservable = Observable.from(Arrays.asList(new String[]{"1", "2", "3"}))
.flatMap(s -> {
return Observable.just(s).subscribeOn(Schedulers.computation());
})
.publish();
stringObservable
.flatMap(s -> {
// do More asyncStuff depending on subscription
return Observable.just(s).subscribeOn(Schedulers.newThread());
})
.subscribe(s -> {
// use result here
});
stringObservable
.subscribe(s -> {
// use immediate result here.
});
stringObservable.connect();
flatMap
沿doOnNext
上Observable
里面flatMap
將導致相同的輸出你的。
onNext()
總是以順序方式調用,因此在flatMap
之后使用doOnNext
也不適合你。 由於在最終subscribe
寫入操作的相同原因在您的情況下不起作用。
以下代碼使用RxJava2編寫。 在RxJava的第1版中,您必須在Thread.sleep
周圍添加try-catch
塊。
ConnectableObservable<String> e = Observable.just("1", "2", "3").publish();
e.flatMap(
s -> Observable.just(s)
.subscribeOn(Schedulers.newThread())
.doOnNext(i -> { // <<<<<<
Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
System.out.println("s1=>" + Thread.currentThread().getName() + "=>" + i);
}))
.subscribe();
e.flatMap(
s -> Observable.just(s)
.subscribeOn(Schedulers.newThread())
.doOnNext(i -> { // <<<<<<
Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
System.out.println("s2=>" + Thread.currentThread().getName() + "=>" + i);
}))
.subscribe();
e.connect();
您可以使用Flowable和parallel實現它:
Flowable.fromIterable(Arrays.asList("1", "2", "3"))
.parallel(3)
.runOn(Schedulers.newThread())
.map(item -> {
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("s1=>" + Thread.currentThread().getName() + "=>" + item);
return Completable.complete();
})
.sequential().subscribe();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.