使RxJava运算符链并发

时间:2016-01-15 04:22:17

标签: java asynchronous reactive-programming rx-java

我刚刚开始使用RxJava。我一直在尝试构建一个数据管道,从不同的源下载大量数据,并以并发方式将数据插入数据库。

我的基本管道表格如下所示:

        Observable.range(1, 5)
            .concatMap((i) -> {
                return Observable.range(i, 2);
            })
            .concatMap((i) -> {
                return Observable.range(i, 2);
            })
            .subscribe((i) -> { System.out.println(i); }, System.out::println,() -> { System.out.println("Complete"); });

每当我调用observeOn而不是运行并打印出上面打印出来的所有数字时,都没有打印出来。为什么是这样?我希望下一个concatMap和subscribe也会使用计算调度程序。代码发布在下面。

        Observable.range(1, 5)
            .concatMap((i) -> {
                return Observable.range(i, 2);
            })
            .observeOn(Schedulers.computation())
            .concatMap((i) -> {
                return Observable.range(i, 2);
            })
            .subscribe((i) -> { System.out.println(i); }, System.out::println,() -> { System.out.println("Complete"); });

2 个答案:

答案 0 :(得分:2)

这是一个猜测,因为你没有提供上下文,但是如果你正在更改线程,你必须阻止,因为主要没有被阻止,你可能在另一个调度程序有机会运行之前终止:

Observable.range(1, 5)
        .concatMap((i) -> {
            return Observable.range(i, 2);
        })
        .observeOn(Schedulers.computation())
        .concatMap((i) -> {
            return Observable.range(i, 2);
        })
        .subscribe((i) -> { System.out.println(i); }, System.out::println,() -> { System.out.println("Complete"); });
// block to let other schedulers finish
Thread.sleep(3000);

答案 1 :(得分:0)

在阅读您的评论以获得更多上下文之后,我假设您想要获取ID列表(项目摘要),然后为每个返回的ID提出一个额外请求以获取每个项目'详细信息,然后对结果(项目)做一些事情。

考虑到您已经拥有构建和触发请求的方法,请返回Observable。您可以包装http相关代码并将Observable推迟,或者从Future创建一个Observable,以防您的http库返回Future

// you have this available
Observable<Summary> = querySummary(summaryId);
Observable<Item> = queryItem(itemId);

我没有运行以下任何代码,因此请将其作为指导。你可以从:

开始
Observable<Item> itemsObservable = querySummary(summaryId)
    .flatMap(summary -> {
        return Observable.from(summary.getItemsIdsList());
    })
    .map(itemId -> {
        return queryItem(itemId);
    });

您正在查询摘要,然后使用flatMap运算符发出单个返回的ID。然后你可以map每个id来发送一个请求。最后,您可以订阅itemsObservable以让各个Item对象流动。

如果要在订阅前保存数据库中的项目,可以在最后doOnNext的尾部插入map并保存每个项目。如果要对每个项目中的值求和,或进行任何聚合,可以使用reduce。依此类推。按照它的方式,最后只有一个.subscribe(),这个代码在主线程中运行(如果你的http库没有任何花哨的线程池功能)。

itemsObservable.doOnNext(item -> {
    // do something in whatever thread it might be running
}).subscribe();

如果要触发摘要请求并异步等待,请触发项目&#39;请求同时在新项ID到达时,您可以像添加.observeOn(Schedulers.io())一样。

Observable<Item> itemsObservable = querySummary(summaryId)
    .observeOn(Schedulers.io()) // from here, continue in the background
    .flatMap(summary -> { // ...

请注意,您告诉Observable链在另一个线程中执行并忘记它。在同样的情况下,这正是你想要的。但是如果你从一个普通的public static void main()方法运行它作为你的程序体,你的程序将在后台执行结束之前关闭,这是预期的。如果你直接处理对线程对象的引用,你应该自己负责join()线程,使主程序等待它们。

由于反应流意味着隐藏线程复杂性,您只需要&#34;说&#34;你想在聚会结束时聚在一起。在这种情况下,要将执行返回到主线程,您可以插入.toBlocking().toList()。然后,您可以安全地在当前主题的订阅的onNext处获得结果。

itemsObservable
    .toBlocking()
    .subscribe(item -> {
        // blocking the main thread
        // do something on each item 
});

或..

itemsObservable
    .toList()
    .subscribe(itemsList -> {
        // blocking the main thread
        // do something with the whole list at once
});

有许多不同的方法可以组成Observable,创建一个或多个流,合并它们,异步运行它们。因此,它可以满足您的需求。

我希望它有所帮助!