J'ai le code suivant en utilisant 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 -> {
},
() -> {
});
J'espérais que le code d'observation, c'est-à-dire le code à l'intérieur de la méthode subscribe (), sera exécuté en parallèle après avoir spécifié le planificateur de calcul. Au lieu de cela, le code est toujours exécuté séquentiellement sur un seul thread. Comment faire en sorte que le code soit exécuté en parallèle avec RxJava api.
RxJava est souvent mal compris en ce qui concerne les aspects asynchrones/multithread. Le codage des opérations multithread est simple, mais comprendre l'abstraction est une autre chose.
Une question commune à propos de RxJava est de savoir comment réaliser la parallélisation ou émettre plusieurs éléments simultanément à partir d’un observable. Bien sûr, cette définition rompt le contrat observable qui stipule que onNext () doit être appelé de manière séquentielle et jamais simultanément par plusieurs threads à la fois.
Pour réaliser le parallélisme, vous avez besoin de plusieurs observables.
Cela fonctionne dans un seul thread:
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()));
Cela fonctionne dans plusieurs threads:
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));
Code et texte proviennent de cet article de blog.
RxJava 2.0.5 introduit des flux parallèles et ParallelFlowable , ce qui rend l’exécution en parallèle plus simple et plus déclarative.
Vous n'avez plus besoin de créer Observable
/Flowable
dans flatMap
, vous pouvez simplement appeler parallel()
sur Flowable
et il retourne ParallelFlowable
.
Ce n'est pas aussi riche en fonctionnalités qu'une Flowable
régulière, car la simultanéité pose de nombreux problèmes avec les contrats Rx, mais vous avez les fonctions de base map()
, filter()
et bien d'autres, qui devraient suffire dans la plupart des cas.
Donc, au lieu de ce flux de @LordRaydenMK answer
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));
maintenant tu peux faire:
Flowable<Integer> vals = Flowable.range(1, 10);
vals.parallel()
.runOn(Schedulers.computation())
.map(i -> intenseCalculation(i))
.sequential()
.subscribe(val -> System.out.println(val));
Vous devez spécifier subscribeOn(Schedulers.computation())
au lieu de observeOn(Schedulers.computation())
à cette fin .. Dans subscribeOn
, vous déclarez dans quel fil vous allez émettre vos valeurs .. Dans observeOn
, vous déclarez dans quel fil vous allez les gérer.
Utiliser flatMap
et spécifier de s'abonner sur Schedulers.computation()
permettra d'obtenir une concurrence.
Voici un exemple plus pratique utilisant Callable
. Nous pouvons voir dans le résultat qu'il faudra environ 2000 millisecondes pour terminer toutes les tâches.
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));
}
Cela vient toujours sur la même séquence. Même sur de nouveaux fils
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();
Sortie 1 ccc RxNewThreadScheduler-1 2 ccc RxNewThreadScheduler-1 3 ccc RxNewThreadScheduler-1 4 ccc RxNewThreadScheduler-1 5 ccc RxNewThreadScheduler-1