RxJava and parallel execution of observer code
我正在使用RxJava Observable api使用以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 Contract,该协议规定onNext()必须被顺序调用,并且一次不能由多个线程同时调用。
要实现并行性,您需要多个Observable。
这在一个线程中运行:
1 2 3 4 5 6 7 | 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())); |
这在多个线程中运行:
1 2 3 4 5 6 | 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,这使得并行执行更简单且更具声明性。
您不再需要在
它的功能不如常规的
因此,而不是来自@LordRaydenMK的流程:
1 2 3 4 5 6 | 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 2 3 4 5 6 7 | Flowable<Integer> vals = Flowable.range(1, 10); vals.parallel() .runOn(Schedulers.computation()) .map(i -> intenseCalculation(i)) .sequential() .subscribe(val -> System.out.println(val)); |
为此必须指定
在
在
使用
这是一个使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 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)); } |
这仍然是相同的顺序。即使在新线程上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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