我是否通过将一个observable转换为一个阻塞的observable来滥用rxJava?

时间:2016-11-23 02:11:44

标签: java rx-java hystrix feign

My API成对地向两个独立的服务进行大约100次下游呼叫。在我将回复发送给客户之前,需要汇总所有回复。我使用hystrix-feign来进行HTTP调用。

我想出了一个优雅的解决方案,直到rxJava docs我发现了以下内容

  

BlockingObservable是一种提供阻塞运算符的Observable。它可用于测试和演示目的,但通常不适合生产应用程序(如果您认为需要使用BlockingObservable,这通常表明您应该重新考虑您的设计)。

我的代码大致如下

List<Observable<C>> observables = new ArrayList<>();
for (RequestPair request : requests) {
    Observable<C> zipped = Observable.zip(
         feignClientA.sendRequest(request.A()),
         feignClientB.sendRequest(request.B()),
         (a, b) -> new C(a,b));
    observables.add(zipped);
}

Collection<D> apiResponse = = new ConcurrentLinkedQueue<>();

Observable
    .merge(observables)
    .toBlocking()
    .forEach(combinedResponse -> apiResponse.add(doSomeWork(combinedResponse)));

return apiResponse;

基于此设置的几个问题:

  1. 根据我的用例
  2. ,toBlocking()是否合理
  3. 我是否理解在主线程到达forEach()之前不会进行实际的HTTP调用
  4. 我已经看到forEach()块中的代码由不同的线程执行,但我无法验证forEach()块中是否可以有多个线程。执行是否并发?

1 个答案:

答案 0 :(得分:1)

更好的选择是返回其他运算符要使用的Observable,但是您可能会使用阻塞代码(但它应该在后台线程上运行。)

public Observable<D> getAll(Iterable<RequestPair> requests) {
    return Observable.from(requests)
    .flatMap(request ->
        Observable.zip(
            feignClientA.sendRequest(request.A()),
            feignClientB.sendRequest(request.B()),
            (a, b) -> new C(a,b)
        )
    , 8)  // maximum concurrent HTTP requests
    .map(both -> doSomeWork(both));
}

// for legacy users of the API
public Collection<D> getAllBlocking(Iterable<RequestPair> requests) {
    return getAll(requests)
        .toList()
        .toBlocking()
        .first();
}
  

我是否理解在主线程到达forEach()之后才会进行实际的HTTP调用

是的,forEach会触发整个操作序列。

  

我已经看到forEach()块中的代码由不同的线程执行,但是我无法验证forEach()块中是否可以有多个线程。那里的执行是并发的吗?

一次只允许一个线程在forEach中执行lambda,但你可能确实看到不同的线程进入那里。