rxJava buffer()用时间来表示背压

时间:2018-04-26 10:20:36

标签: rx-java2 project-reactor

根据JavaDoc,不按时运行的buffer运算符版本支持背压:

http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable.html#buffer-int-

但是,任何涉及基于时间的缓冲区的buffer版本都不支持背压,例如

http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable.html#buffer-long-java.util.concurrent.TimeUnit-int-

我理解这是因为一旦时间到了,你就无法阻止它,例如interval运算符,由于同样的原因不支持背压。

我想要的是一个基于大小和时间的缓冲操作符,并通过将背压信号传播到上游和时间滴答生成器来完全支持背压,如下所示:

someFlowable() .buffer( Flowable.interval(1, SECONDS).onBackpressureDrop(), 10 );

所以现在我可以放弃背压信号。

这是rxJava2目前可以实现的吗? Project-Reactor怎么样?

4 个答案:

答案 0 :(得分:1)

DisposableSubscriber用作订户时,我遇到了https://stackoverflow.com/a/55136139/6719538解决方案的问题,据我所知,该转换器不考虑来自下游订户的呼叫Suscription#request(它可能会溢出他们)。我创建了在生产环境中经过测试的版本-BufferTransformerHonorableToBackpressure.javafang-yang-非常尊重想法。

答案 1 :(得分:0)

已经有一段时间了,但是我又看了一遍,以某种方式使我震惊:

public static <T> FlowableTransformer<T, List<T>> buffer(
    int n, long period, TimeUnit unit)
{
    return o ->
        o.groupBy(__ -> 1)
         .concatMapMaybe(
             gf ->
                 gf.take(n)
                   .take(period, SECONDS)
                   .toList()
                   .filter(l -> !l.isEmpty())
         );
}

几乎按照我的描述做。 如果我是正确的话,那是完全背压的,它将缓冲n个项目,或者如果没有收集足够的项目,将在指定的时间之后缓冲

答案 2 :(得分:0)

我又做了一个尝试,导致了一个看起来过于有效的解决方案(TM)

要求

  1. 一个缓冲运算符,该缓冲运算符在经过一定时间间隔后或缓冲区达到最大大小(以先到者为准)释放缓冲区
  2. 运算符必须被完全背压,即,如果请求从下游停止,则缓冲区运算符不应发出数据,也不应引发任何异常(如starndard Flowable.buffer(interval,TimeUnit)运算符那样)。也不应该以无界模式使用其源/上游
  3. 通过组合现有/已实现的运算符来实现。

为什么会有人想要它?

当我想在无限/长时间运行的流上实现缓冲时,就需要这种运算符。我想缓冲以提高效率,但是标准Flowable.buffer(n)在这里不合适,因为“无限”流可以发射k

解决方案概述

该解决方案基于https://github.com/akarnokd/RxJava2Extensions项目中实现的generateAsyncpartialCollect运算符。剩下的就是starndard RxJava2。

  1. 首先将上游所有值包装在容器类C
  2. 然后merge与源正在使用generateAsync的流一起传输。该流使用switchMap发出C的实例,这些实例实际上是超时信号。
  3. 这两个合并的流正在流入partialCollect,该流持有对“ API”对象的引用,以向generateAsync上游发送项目。这是一种反馈循环,它从paritialCollect通过“ API”对象到generateAsync,然后反馈到partialCollect。这样,partialCollect可以在接收到缓冲区中的第一个元素后发出将有效启动超时的信号。如果在超时之前缓冲区未满,它将导致一个空C(不包含任何值)的实例流回partialCollect。它将检测到它为超时信号,并向下游释放聚合缓冲区。如果由于达到最大大小而释放了缓冲区,它将被释放,并且下一个项目将开始另一个超时。任何超时信号(空C的实例)迟到,也就是由于达到最大大小而在释放缓冲区之后,将被忽略。可能的原因是,实例化并发送超时信号项的partialCollect可能会流回去。检查该物品的身份可以检测到延迟超时还是合法超时信号。

代码https://gist.github.com/artur-jablonski/5eb2bb470868d9eeeb3c9ee247110d4a

答案 3 :(得分:0)

我最近遇到了问题,这是我的实现。可以这样使用:

    Flowable<List<T>> bufferedFlow = (some flowable of T)
                              .compose(new BufferTransformer(1, TimeUnit.MILLISECONDS, 8))

它通过您指定的计数支持背压。

以下是实现:https://gist.github.com/driventokill/c49f86fb0cc182994ef423a70e793a2d