我正在使用RxJava异步处理servlet请求。在每个请求期间,使用flatMap运算符对远程服务API进行大量异步调用。
由于资源限制,我需要限制针对该API的并发请求总数。对于使用其并发参数在单个flatMap中调用API的单个Rx流,这将是微不足道的。但是我的应用程序中有多个独立的流(每个ServletRequest基本上都有一个),每个流都有多个对API的flatMap调用。
所以我认为我必须将所有远程请求汇集到执行实际调用的单例流中,然后才能轻松限制并发性。但是,将API响应恢复到原始流中似乎并非易事。另外,在这样的构造中保持背压似乎很复杂。
另一种选择是使用传统的信号量,但我不确定它的阻塞行为是否适合Rx。
那么有一个既定的模式来实现这样的东西?或者我错过了一个聪明的运算符组合,完全避免了这些复杂性?
答案 0 :(得分:0)
在RxJava中,您可以从常规Java执行程序创建自己的调度程序:
ExecutorService exec= Executors.newFixedThreadPool(2); //2 Fixed threads
Schedulers.from(exec);
因此,只需为每个资源创建一个具有有限数量线程的执行程序,并在访问资源时使用该特定调度程序。有限数量的线程将限制并发呼叫的数量。
编辑:
显然我误解了这个问题。如果呼叫是异步的,您可以尝试使用Rx的背压来管理它们。以下是关于如何使用Rx管理此类调用的想法:
您创建了一个"资源许可可观察的"只要调用API ,就会发出某种东西(某种代币)。其创建令牌(许可)的速率将是该API的最大使用率。每当一些observable需要调用API时,只需压缩调用带有permit observable的调用。 Zip运算符将阻塞,直到许可证可用,将API调用限制为允许生成速率
这是一个发布时间戳的permit observable的简单实现:
public class PermitObservable extends Observable<Long> {
private final long msBetweenEmissions;
public PermitObservable(long msBetweenEmissions) {
super(new SyncOnSubscribe<Long, Long>() {
@Override
protected Long generateState() {
return System.currentTimeMillis();
}
@Override
protected Long next(Long state, Observer<? super Long> observer) {
long nextEmissionAt = state + msBetweenEmissions;
long timeToWait = nextEmissionAt - System.currentTimeMillis();
if (timeToWait > 0) {
try {
Thread.sleep(timeToWait);
} catch (InterruptedException e) {
observer.onError(e);
}
}
long now = System.currentTimeMillis();
observer.onNext(Long.valueOf(now)); // Permit emission
return now;
}
});
this.msBetweenEmissions = msBetweenEmissions;
}
}
答案 1 :(得分:0)
签出Scheduler.when()
。它允许用户从现有调度程序构建修改后的调度程序,而不用创建新的线程池。像使用Schedulers.io()一样,但限制活动线程的数量。或限制Schedulers.computation()上onNexts的数量。