我使用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使代码并行运行。
答案 0 :(得分:49)
当涉及到异步/多线程方面时,RxJava经常被误解。多线程操作的编码很简单,但理解抽象是另一回事。
关于RxJava的常见问题是如何从Observable实现并行化或同时发出多个项目。当然,这个定义违反了Observable Contract,它声明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));
答案 1 :(得分:9)
RxJava 2.0.5引入了paralell flows和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));
答案 2 :(得分:2)
为此目的,您必须指定subscribeOn(Schedulers.computation())
而不是observeOn(Schedulers.computation())
。
在subscribeOn
中,您声明要在哪个线程中发出值。
在observeOn
中,您声明要处理的线程并观察它们。
答案 3 :(得分:1)
使用Schedulers.computation()
并指定在Callable
上订阅将实现并发。
这是一个使用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));
}
的更实用的例子,从输出中我们可以看到完成所有任务需要大约2000毫秒。
{{1}}
答案 4 :(得分:0)
这仍然是相同的序列。即使是新线程
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