RxJava和观察者代码的并行执行

时间:2016-02-16 07:00:39

标签: java system.reactive rx-java

我使用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使代码并行运行。

5 个答案:

答案 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));

代码和文字comes from this blog post.

答案 1 :(得分:9)

RxJava 2.0.5引入了paralell flowsParallelFlowable,这使得并行执行更加简单且更具声明性。

您不再需要在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