RxJava和rx.exceptions.MissingBackpressureException异常

时间:2016-01-02 20:53:04

标签: java rx-java rx-android

我正在尝试使用一个非常基本的基于RxJava的应用程序。我定义了以下Observable类,它从文件中读取并返回行:

public Observable<String> getObservable() throws IOException
    {
        return Observable.create(subscribe -> {
            InputStream in = getClass().getResourceAsStream("/trial.txt");
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line = null;
            try {
                while((line = reader.readLine()) != null)
                {
                    subscribe.onNext(line);
                }
            } catch (IOException e) {
                subscribe.onError(e);
            }
            finally {
                subscribe.onCompleted();
            }
        });
    }

接下来我定义了子代码:

public static void main(String[] args) throws IOException, InterruptedException {
        Thread thread = new Thread(() ->
        {
            RxObserver observer = new RxObserver();
            try {
                observer.getObservable()
                        .observeOn(Schedulers.io())
                        .subscribe( x ->System.out.println(x),
                                    t -> System.out.println(t),
                                    () -> System.out.println("Completed"));

            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        thread.start();
        thread.join();
    }

该文件接近50000条记录。运行应用程序时,我收到“rx.exceptions.MissingBackpressureException”。我已经阅读了一些文档,并且按照建议,我尝试在调用链中添加“.onBackpressureBuffer()”方法。但后来我没有得到例外,但完成的电话也没有被解雇。

处理具有快速生成Observable的场景的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

第一个问题是readLine逻辑忽略了背压。您可以在onBackpressureBuffer()开始之前应用observeOn,但最近添加了SyncOnSubscribe,您可以逐个生成值并负责背压:

SyncOnSubscribe.createSingleState(() => {
    try {
        InputStream in = getClass().getResourceAsStream("/trial.txt");
        return new BufferedReader(new InputStreamReader(in));
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }
},
(s, o) -> {
    try {
        String line = s.readLine();
        if (line == null) {
            o.onCompleted();
        } else {
            o.onNext(line);
        }
    } catch (IOException ex) {
        s.onError(ex);
    }
},
s -> {
    try {
       s.close();
    } catch (IOException ex) {
    }
});

第二个问题是你的线程将在io线程上的所有元素都被传递之前完成,因此主程序退出。删除observeOn,添加.toBlocking或使用CountDownLatch

RxObserver observer = new RxObserver();
try {

    CountDownLatch cdl = new CountDownLatch(1);

    observer.getObservable()
           .observeOn(Schedulers.io())
           .subscribe( x ->System.out.println(x),
                       t -> { System.out.println(t); cdl.countDown(); },
                       () -> { System.out.println("Completed"); cdl.countDown(); });

    cdl.await();
 } catch (IOException | InterruptedException e) {
     e.printStackTrace();
 }

答案 1 :(得分:1)

这里的问题是 observeOn 运算符,因为每个Observer的onNext()调用都被调度在一个单独的线程上调用,你的Observable不断地在循环中生成那些调度的调用。订户(observeOn)的容量。

如果你保持同步,Observable将不会发出下一个元素,直到订阅者完成前一个元素,因为它在一个线程上完成,你将不再有背压问题。

如果您仍想使用 observeOn ,则必须在Observable的 OnSubscribe#calls 方法中实施背压逻辑