RxJava Observable APIを使用して次のコードを持っています:
Observable<Info> observable = fileProcessor.processFileObservable(processedFile.getAbsolutePath());
observable
.buffer(10000)
.observeOn(Schedulers.computation())
.subscribe(recordInfo -> {
_logger.info("Running stage2 on thread with id : " + Thread.currentThread().getId());
for(Info info : recordInfo) {
// some I/O operation logic
}
},
exception -> {
},
() -> {
});
私の期待は、計算スケジューラを指定した後、観測コード、つまりsubscribe()メソッド内のコードが並列に実行されることでした。代わりに、コードは引き続き単一のスレッドで順次実行されます。 RxJava APIを使用してコードを並列に実行する方法。
RxJavaは、非同期/マルチスレッドの側面に関して誤解されることがよくあります。マルチスレッド操作のコーディングは簡単ですが、抽象化を理解することは別のことです。
RxJavaに関する一般的な質問は、並列化を実現する方法、またはObservableから複数のアイテムを同時に出力する方法です。もちろん、この定義は、onNext()が一度に複数のスレッドによって同時に呼び出されることはなく、同時に呼び出される必要があることを示すObservable Contractを破ります。
並列処理を実現するには、複数のObservableが必要です。
これは単一のスレッドで実行されます:
Observable<Integer> vals = Observable.range(1,10);
vals.subscribeOn(Schedulers.computation())
.map(i -> intenseCalculation(i))
.subscribe(val -> System.out.println("Subscriber received "
+ val + " on "
+ Thread.currentThread().getName()));
これは複数のスレッドで実行されます:
Observable<Integer> vals = Observable.range(1,10);
vals.flatMap(val -> Observable.just(val)
.subscribeOn(Schedulers.computation())
.map(i -> intenseCalculation(i))
).subscribe(val -> System.out.println(val));
コードとテキスト は、このブログ投稿からのものです。
RxJava 2.0.5では、 paralellフロー および ParallelFlowable が導入されました。これにより、並列実行がより簡単で宣言的になります。
Observable
内にFlowable
/flatMap
を作成する必要はなくなりました。Flowable
でparallel()
を呼び出すだけで、ParallelFlowable
。
同時実行はRxコントラクトで多くの問題を引き起こすため、通常のFlowable
ほど機能が豊富ではありませんが、基本的なmap()
、filter()
などがあります。ほとんどの場合で十分です。
@LordRaydenMKからのこのフローの代わりに答え
Observable<Integer> vals = Observable.range(1,10);
vals.flatMap(val -> Observable.just(val)
.subscribeOn(Schedulers.computation())
.map(i -> intenseCalculation(i))
).subscribe(val -> System.out.println(val));
できるようになりました:
Flowable<Integer> vals = Flowable.range(1, 10);
vals.parallel()
.runOn(Schedulers.computation())
.map(i -> intenseCalculation(i))
.sequential()
.subscribe(val -> System.out.println(val));
そのためには、subscribeOn(Schedulers.computation())
の代わりにobserveOn(Schedulers.computation())
を指定する必要があります。 subscribeOn
で、値を出力するスレッドを宣言します。 observeOn
で、どのスレッドでそれらを処理および監視するかを宣言します。
flatMap
を使用し、Schedulers.computation()
をサブスクライブするように指定すると、並行性が実現します。
出力からのCallable
を使用したより実用的な例は、すべてのタスクを完了するのに約2000ミリ秒かかることがわかります。
static class MyCallable implements Callable<Integer> {
private static final Object CALLABLE_COUNT_LOCK = new Object();
private static int callableCount;
@Override
public Integer call() throws Exception {
Thread.sleep(2000);
synchronized (CALLABLE_COUNT_LOCK) {
return callableCount++;
}
}
public static int getCallableCount() {
synchronized (CALLABLE_COUNT_LOCK) {
return callableCount;
}
}
}
private static void runMyCallableConcurrentlyWithRxJava() {
long startTimeMillis = System.currentTimeMillis();
final Semaphore semaphore = new Semaphore(1);
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
Observable.just(new MyCallable(), new MyCallable(), new MyCallable(), new MyCallable())
.flatMap(new Function<MyCallable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull MyCallable myCallable) throws Exception {
return Observable.fromCallable(myCallable).subscribeOn(Schedulers.computation());
}
})
.subscribeOn(Schedulers.computation())
.subscribe(new Observer<Object>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Object o) {
System.out.println("onNext " + o);
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
if (MyCallable.getCallableCount() >= 4) {
semaphore.release();
}
}
});
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
System.out.println("durationMillis " + (System.currentTimeMillis()-startTimeMillis));
}
これは同じシーケンスで行われます。新しいスレッドでも
Observable ob3 = Observable.range(1、5);
ob3.flatMap(new Func1<Integer, Observable<Integer>>() {
@Override
public Observable<Integer> call(Integer pArg0) {
return Observable.just(pArg0);
}
}).subscribeOn(Schedulers.newThread()).map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer pArg0) {
try {
Thread.sleep(1000 - (pArg0 * 100));
System.out.println(pArg0 + " ccc " + Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
return pArg0;
}
}).subscribe();
出力1 ccc RxNewThreadScheduler-1 2 ccc RxNewThreadScheduler-1 3 ccc RxNewThreadScheduler-1 4 ccc RxNewThreadScheduler-1 5 ccc RxNewThreadScheduler-1