Rxjava-可观察序列中元素的分组/批处理突发

Rxjava-可观察序列中元素的分组/批处理突发,java,rx-java,rx-java2,Java,Rx Java,Rx Java2,我有一个可观察的序列。当插入第一个元素时,我想启动一个计时器,并在计时器的时间跨度内批处理后续插入的元素。然后,在序列中插入另一个元素之前,计时器不会再次启动 --------|=====timespan====|---------------|=====timespan====|--------------> 1 2 3 4 5 6 将产生: [1,2,3,4,5], [6] 我尝试了Observable.buffe

我有一个可观察的序列。当插入第一个元素时,我想启动一个计时器,并在计时器的时间跨度内批处理后续插入的元素。然后,在序列中插入另一个元素之前,计时器不会再次启动

--------|=====timespan====|---------------|=====timespan====|-------------->
        1  2 3 4    5                     6 
将产生:

[1,2,3,4,5], [6] 
我尝试了
Observable.buffer()
timespan
,但是从我的实验中,我可以看到,一旦我们订阅了可观察序列,计时器就会启动,并且一旦上一个计时器完成,计时器就会重新启动

因此,使用与上一个示例相同的序列,并将
buffer()
timespan
一起使用,我将得到如下结果:

|=====timespan====|=====timespan====|=====timespan====|=====timespan====|-->
        1  2 3 4                          5 6           
这将产生以下结果:

[1,2,3,4], [], [5,6], []
这本质上是与相同的问题,但对于java来说是相反的


所以问题是,因为我不想太多地延迟我的流,所以我想要一个非常短的计时器,而且这个计时器会非常密集。我可以简单地过滤空列表,但我认为这对CPU影响太大。

窗口
操作符将充当
缓冲区
,您不能直接使用它

这个想法是通过第一个可观察到的发射(我称之为插入)来控制
定时器。为此,您必须包含第三个参数来链接两个观测值(
stopWatch
Subject,在下面的解决方案中)

@测试
公共无效停止观察观察(){
Subject stopWatch=PublishSubject.create();
可观察的插入=插入();
//共享以将其用作计时器(查找第一次发射)
//以及接收物品
可观察的共享=insertions.share();
//对于每个插入的发射,我们启动一个新的计时器
//但只有第一个被发射
//其他人被takeUntil(秒表)拦住
可观察窗口=共享
.flatMap(e->Observable.timer(3,TimeUnit.SECONDS).takeUntil(秒表));
共享缓冲区(窗口)
//每次生成一个窗口时,我们都会杀死所有当前计时器
.doOnNext(e->stopWatch.onNext(0L))
.blockingSubscribe(System.out::println);
}
//正在随机提交的插入生成器
私有可观察插入(){
原子长al=新原子长(0);
返回可见。生成((发射器)-发射器)->{
如果(al.getAndIncrement()%4==0){
Long-timeToWait=Long.parseLong(RandomStringUtils.randomNumeric(1));
System.out.println(“睡眠时间:+timeToWait”);
睡眠(时间等待*1000);
}否则{
睡眠(500);
}
emitter.onNext(al.get());
}).subscribeOn(Schedulers.newThread());
}

第一种解决方案的缺点是每次插入都会启动一个
计时器(它可能是CPU密集型的)。这里是另一个只启动一个计时器的解决方案(我认为这样更有效:

@测试
公共无效停止观察观察(){
可观察的插入=插入();
可观察的共享=insertions.share();
AtomicBoolean timerOn=新的AtomicBoolean(false);
可观察窗口=共享
.flatMap(e->timerOn.get()?Observable.empty():Observable.timer(3,TimeUnit.SECONDS)
.doOnSubscribe(x->timerOn.set(true))
);
共享缓冲区(窗口)
//每次生成一个窗口时,我们都会杀死所有当前计时器
.doOnNext(e->timerOn.set(false))
.blockingSubscribe(System.out::println);
}

这听起来有点像window()函数。您是否检查过它是否满足您的需要?window是否与buffer()完全相同,而是以可观察值作为输出?
    @Test
    public void stop_watch_observable() {

        Subject<Long> stopWatch = PublishSubject.create();

        Observable<Long> insertions = insertions();

        //share to use it as a timer (looking for the first emission)
        //and to recieve the items
        Observable<Long> shared = insertions.share();

        //for each emission of insertions we start a new timer
        //but only the first one is emitted
        //the others are stopped by the takeUntil(stopWatch)
        Observable<Long> window = shared
                .flatMap(e -> Observable.timer(3, TimeUnit.SECONDS).takeUntil(stopWatch));

        shared.buffer(window)
                //each time a window is generated we kill all the current timers
                .doOnNext(e -> stopWatch.onNext(0L))
                .blockingSubscribe(System.out::println);
    }

    // insertions generator which is comming randomly
    private Observable<Long> insertions() {
        AtomicLong al = new AtomicLong(0);
        return Observable.generate((Emitter<Long> emitter) -> {
            if (al.getAndIncrement() % 4 == 0) {
                Long timeToWait = Long.parseLong(RandomStringUtils.randomNumeric(1));
                System.out.println("sleeping for: " + timeToWait);
                sleep(timeToWait * 1000);
            } else {
                sleep(500);
            }
            emitter.onNext(al.get());
        }).subscribeOn(Schedulers.newThread());
    }