RxJava:循环中的异步调用

时间:2017-10-08 20:41:50

标签: java loops asynchronous rx-java

我有一个整数列表,对于每个整数,我想从数据库中获取一个字符串值,并将其放入一个Map中,其中Integer是父列表中的int值,String是从中取出的字符串值数据库。我也想要,让字符串并行运行。

这就是我用RxJava实现的方法。我的代码有效,我得到了预期的结果,但我不认为提取名称是并行的。

public Observable<Map<Integer, String>> getVitalsForConnectedDevices(int accountId) {
    List<Integer> ids = Lists.newArrayList(2, 3, 5);

    return Observable<Map<Integer, String>> obs = Observable.from(ids)
            .flatMap((Func1<Integer, Observable<Map.Entry<Integer, String>>>) integer
                    -> Observable.just(Maps.immutableEntry(integer, deviceDAO.getVitalName(integer)))
                    .subscribeOn(Schedulers.io()), 20)
            .toMap(entry -> entry.getKey(), entry -> entry.getValue());
}

这是getVitalName()方法

public String getVitalName(int vitalId) {
    log.debug("id: " + vitalId);
    String query = "SELECT name FROM vitals WHERE vital_id=?";
    String name = v1JdbcTemplate.queryForObject(query, String.class, vitalId);
    log.debug("name: " + name);
    return name;
}

按以下顺序打印上述函数的调试语句:

09-10-2017 02:05:37 DEBUG DeviceDAO:118 - id: 2
09-10-2017 02:05:37 DEBUG DeviceDAO:121 - name: Steps
09-10-2017 02:05:37 DEBUG DeviceDAO:118 - id: 3
09-10-2017 02:05:37 DEBUG DeviceDAO:121 - name: Floors
09-10-2017 02:05:37 DEBUG DeviceDAO:118 - id: 5
09-10-2017 02:05:37 DEBUG DeviceDAO:121 - name: Distance

如果它是并行运行的,那么它不应该先打印所有id的名字,以后再打印吗?我在这做错了什么?如何让它们并行运行?

1 个答案:

答案 0 :(得分:1)

  

不应该首先打印所有ID并稍后命名

答案是否定的,因为您要从数据库中请求每个id一个String。结果完成后,将Id和String打包到一个Entry中并将其向下推送到管道中。请注意,如果所有flatMaps完成或发出错误,toMap将仅成功完成。所以可能会等待一段时间才能获得最终结果。

作为示例:您迭代超过5个ID。所有请求都是并行触发的。由于负载,服务器处于困境,因此一些请求将花费一些时间。让我们说一个请求已经完成但只有一个。仅在最后一个请求完成时,结果Map&lt;&gt;将推送给订户。如果这是你想要的,那么我建议你返回一个&lt;&gt;不是观察者。

以下是输出测试:

@Test
void name() throws Exception {
    Observable<Tuple2<Integer, String>> tuple2Observable = Observable.just(1, 2, 3, 4, 5, 6)
            .flatMap(integer ->
                    Observable.fromCallable(() -> getVitalName(integer))
                            .subscribeOn(Schedulers.io())
                            .doOnNext(s -> System.out.println("Value:: " + Thread.currentThread().getName() + "-" + Instant.now()))
                            .map(s -> Tuple.of(integer, s))
            ).doOnComplete(() -> System.out.println("Finished:: " + Thread.currentThread().getName() + "-" + Instant.now()));

    tuple2Observable.test()
            .await();
}

public String getVitalName(int vitalId) throws Exception {
    System.out.println("getVitalName method called with vitalId = " + vitalId + "-" + Thread.currentThread().getName() + "-" + Instant.now());

    Thread.sleep(500);

    String name = "le fake value";
    return name;
}

你看,确实在不同的线程上同时创建了calles,并且当所有请求都完成时,observable完成了。

getVitalName method called with vitalId = 4-RxCachedThreadScheduler-4-2017-10-08T21:20:43.785Z
getVitalName method called with vitalId = 6-RxCachedThreadScheduler-6-2017-10-08T21:20:43.786Z
getVitalName method called with vitalId = 5-RxCachedThreadScheduler-5-2017-10-08T21:20:43.785Z
getVitalName method called with vitalId = 1-RxCachedThreadScheduler-1-2017-10-08T21:20:43.785Z
getVitalName method called with vitalId = 2-RxCachedThreadScheduler-2-2017-10-08T21:20:43.784Z
getVitalName method called with vitalId = 3-RxCachedThreadScheduler-3-2017-10-08T21:20:43.787Z
Value:: RxCachedThreadScheduler-4-2017-10-08T21:20:44.303Z
Value:: RxCachedThreadScheduler-6-2017-10-08T21:20:44.303Z
Value:: RxCachedThreadScheduler-1-2017-10-08T21:20:44.304Z
Value:: RxCachedThreadScheduler-2-2017-10-08T21:20:44.304Z
Value:: RxCachedThreadScheduler-3-2017-10-08T21:20:44.304Z
Value:: RxCachedThreadScheduler-5-2017-10-08T21:20:44.304Z
Finished:: RxCachedThreadScheduler-4-2017-10-08T21:20:44.317Z