FlowableOperator本身是否支持背压?

时间:2018-02-22 14:37:20

标签: rx-java2 backpressure

我已经按照RxJava2 wiki(https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0#operator-targeting-lift)中的描述实现了FlowableOperator,除了我在onNext()操作中执行了类似的操作:

public final class MyOperator implements FlowableOperator<Integer, Integer> {

...

static final class Op implements FlowableSubscriber<Integer>, Subscription {

    @Override
    public void onNext(Integer v) {
        if (v % 2 == 0) {
          child.onNext(v * v);
        }  
    }
   ...
  }
}

此运算符是链的一部分,我在其中创建了带有背压降的Flowable。从本质上讲,它看起来几乎是这样的:

Flowable.<Integer>create(emitter -> myAction(), DROP)
        .filter(v -> v > 2)
        .lift(new MyOperator())
        .subscribe(n -> doSomething(n));

我遇到了以下问题:

  • 发生背压,因此doSomething(n)无法处理即将到来的上游
  • 由于选择了Backpressure策略,
  • 项目被删除
  • 但doSomething(n)在执行删除后并且doSomething(n)准备处理新项目时从未收到新项目

回顾David Karnok的优秀博文http://akarnokd.blogspot.fr/2015/05/pitfalls-of-operator-implementations.html,似乎我需要在request(1)方法中添加onNext()。但那是RxJava1 ......

所以,我的问题是:RxJava2中有足够的解决方法来处理我的背压问题吗?或者我的操作员是否必须实施有关Atomics的所有内容,排除https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0#atomics-serialization-deferred-actions中描述的内容以正确处理我的背压问题?

注意:我添加了request(1),它似乎有效。但是我无法弄清楚它是否足够,或者我的操作员是否需要排队排水和原子的棘手问题。

提前致谢!

2 个答案:

答案 0 :(得分:1)

  

FlowableOperator本身是否支持背压?

Subscriber是为给定的下游Subscriber调用的接口,应该返回一个新的Subscriber,它包装下游并调制在一个或两个方向上传递的Reactive Streams事件。背压支持是Function<Subscriber, Subscriber>实现的责任,而不是这个特定的功能接口。它可能是Subscriber但是一个单独的命名接口被认为更有用,更不容易出现过载冲突。

  

需要在onNext()[...]中添加一个请求(1)   但是我无法弄清楚它是否足够,或者我的操作员是否需要排队排水和原子的棘手问题。

是的,你也必须在RxJava 2中这样做。由于RxJava 2 request不是一个类,它没有v1的方便Subscription方法。您必须将onSubscribe保存在upstream.request(1)中,并在onNext中的相应路径上致电final class FilterOddSubscriber implements FlowableSubscriber<Integer>, Subscription { final Subscriber<? super Integer> downstream; Subscription upstream; // ... @Override public void onSubscribe(Subscription s) { if (upstream != null) { s.cancel(); } else { upstream = s; // <------------------------- downstream.onSubscribe(this); } } @Override public void onNext(Integer item) { if (item % 2 != 0) { downstream.onNext(item); } else { upstream.request(1); // <------------------------- } } @Override public void request(long n) { upstream.request(n); } // the rest omitted for brevity } 。对于你的情况,它应该足够了。

我已经使用新的部分更新了wiki,明确解释了这个案例:

https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0#replenishing

\b([1-9]|[1-5]\d|60)\b

答案 1 :(得分:0)

是的,你必须做那些棘手的事情......

我会避免编写操作符,除非你非常确定你在做什么?使用默认运算符几乎可以实现一切......

  

编写运算符,类似源(fromEmitter)或类似中间   (flatMap)在RxJava中一直是一项艰巨的任务。有许多   服从的规则,许多情况要考虑,但同时,许多   (合法的)快捷方式,用于构建性能良好的代码。现在写   专门针对2.x的运算符比1.x难10倍。如果   你想利用所有先进的第四代功能   甚至比上面硬2-3倍(总共30倍)。

解释了一些棘手的问题:https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0