我有一个observable,可以从数据库游标的快速流中生成数据。我希望以每秒x项的速率限制输出。到目前为止,我一直在使用文档中描述的Callstack阻止:
observable.map(f -> {
ratelimiter.acquire(); // configured limiter to only allow
});
这项工作正常,但出于好奇,有没有更好的方法来处理背压?
韩国社交协会
答案 0 :(得分:2)
使用sample
(throttleLast)运算符:
Observable<T> throttled =
observable.sample(1 / rate, TimeUnit.MILLISECONDS);
答案 1 :(得分:2)
您可以尝试将rx.Observable#onBackpressureBuffer()
与定制订阅者结合使用,定制订阅者每秒会定期请求n
个项目。但是,你必须 hard 一秒钟的采样。
注意 .subscribeOn()
和.toBlocking()
只是为了让主要方法不会立即退出。
public class BackpressureTest {
public static void main(final String[] args) {
Observable.range(1, 1000)
.compose(Observable::onBackpressureBuffer) // consume source immediately, but buffer it
.lift(allowPerSecond(3)) // via operator using custom subscriber request n items per second
.subscribeOn(Schedulers.computation())
.toBlocking()
.subscribe(System.out::println);
}
private static <T> Observable.Operator<T, T> allowPerSecond(final int n) {
return upstream -> periodicallyRequestingSubscriber(upstream, n);
}
private static <T> Subscriber<T> periodicallyRequestingSubscriber(final Subscriber<T> upstream, final int n) {
return new Subscriber<T>() {
@Override
public void onStart() {
request(0); // request 0 so that source stops emitting
Observable.interval(1, SECONDS).subscribe(x -> request(n)); // every second request n items
}
@Override
public void onCompleted() {
upstream.onCompleted();
}
@Override
public void onError(final Throwable e) {
upstream.onError(e);
}
@Override
public void onNext(final T integer) {
upstream.onNext(integer);
}
};
}
}
答案 2 :(得分:0)
@michalsamek的回答似乎是正确的,尽管背压仅适用于Flowables。我已经更正了他的订阅者,因此它可以执行所请求的内容。
在不同时间连续使用时也存在轻微问题。
private static <T> FlowableOperator<T, T> allowPerMillis(int millis) {
return observer -> new PeriodicallyRequestingSubscriber<>(observer, millis);
}
Observable.range(1, 100)
.observeOn(Schedulers.io())
.toFlowable(BackpressureStrategy.BUFFER)
.compose(Flowable::onBackpressureBuffer)
.lift(allowPerMillis(200))
.subscribe(value -> System.out.println(System.currentTimeMillis() % 10_000 + " : " + value));
public class PeriodicallyRequestingSubscriber<T> implements Subscriber<T> {
private final Subscriber<T> upstream;
private final int millis;
// If there hasn't been a request for a long time, do not flood
private final AtomicBoolean shouldRequest = new AtomicBoolean(true);
public PeriodicallyRequestingSubscriber(Subscriber<T> upstream, int millis) {
this.upstream = upstream;
this.millis = millis;
}
@Override
public void onSubscribe(Subscription subscription) {
Observable
.interval(millis, TimeUnit.MILLISECONDS)
.subscribe(x -> {
if (shouldRequest.getAndSet(false))
subscription.request(1);
});
}
@Override
public void onNext(T t) {
shouldRequest.set(true);
upstream.onNext(t);
}
@Override
public void onError(Throwable throwable) {
upstream.onError(throwable);
}
@Override
public void onComplete() {
upstream.onComplete();
}
}