![](/img/trans.png)
[英]Why Parallel execution not happening for multiple RXJava Observables?
[英]RxJava and parallel execution of observer code
我有以下使用 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 并发地发出多个项目。 当然,这个定义打破了 Observable 契约,该契约规定 onNext() 必须按顺序调用,并且一次不能被多个线程同时调用。
要实现并行性,您需要多个 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 引入了并行流和ParallelFlowable ,这使得并行执行更简单、更具声明性。
你不再需要创建Observable
/ Flowable
内flatMap
,您也可以叫parallel()
上的Flowable
并返回ParallelFlowable
。
它不像常规Flowable
那样功能丰富,因为并发会引发 Rx 合约的许多问题,但是您有基本的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<Integer> 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.