RxScala带超时的递归流

RxScala带超时的递归流,scala,reactive-programming,rx-java,rx-scala,Scala,Reactive Programming,Rx Java,Rx Scala,我试图递归地定义一个可观察的对象,它要么从一个主体发出项目,要么,如果经过一定的时间,一个默认值,在这种情况下,我使用计时器的默认值零。我正在使用RxScala,并从以下代码开始: val s = PublishSubject[Int]() def o: Observable[Unit] = { val timeout = Observable.timer(1 second) Observable.amb(s, timeout) .first .concatMap((v

我试图递归地定义一个可观察的对象,它要么从一个主体发出项目,要么,如果经过一定的时间,一个默认值,在这种情况下,我使用计时器的默认值零。我正在使用RxScala,并从以下代码开始:

val s = PublishSubject[Int]()

def o: Observable[Unit] = {
  val timeout = Observable.timer(1 second)
  Observable.amb(s, timeout)
    .first
    .concatMap((v) => {
      println(v)
      o
    })
}

ComputationScheduler().createWorker.schedule {
  var value = 0
  def loop(): Unit = {
    Thread.sleep(5000)
    s.onNext(value + 1)
    value += 1
    loop()
  }
  loop()
}

o.toBlocking.last
这看起来应该是可行的,但输出令人困惑。每隔一个零序列包含两个,而不是预期的四个。发出两个零,剩余的三秒钟过去,但没有输出

0
0
0
0
1
0
0
2
0
0
0
0
3
0
0
4
0
0
0
0
5
0
0
6
0
0
0
0
7
0
0
8

这确实令人费解!所以这里有一个理论:

事实上,您的代码每5秒产生4次滴答声,而不是5次。 4号有一个竞赛条件,首先是超时,然后是工人,然后是超时,等等。 所以,序列不是00001002 00003。。。将其视为0000 1002 0000

因此,您可能会遇到两个不同的问题,如果不加以处理,我无法做很多事情,但您可以尝试:

在o中添加一个序列号,这样您就可以看到哪些TIMOUT没有赢得比赛。 将值从1秒和5秒更改为彼此不是倍数的值,如1.5秒和5秒。这可能有助于你解决一个问题,集中精力解决另一个问题。 每秒打印一个无关的外部工作程序。大约在0.3秒后启动。也许能让你更好地了解分水岭在哪里。
将代码重构为以下内容将在我的机器上生成预期结果:

object Test {
  def main(args: Array[String]) {
    val s = PublishSubject[Int]()

    val timeout = Observable.timer(1 second)

    def o: Observable[Unit] = {
      Observable.amb(s, timeout).first
        .concatMap((v) => {
          println(v)
          o
        })
    }

    var value = 0
    NewThreadScheduler().createWorker.scheduleRec {
      Thread.sleep(5000)
      value += 1
      s.onNext(value)
    }

    o.toBlocking.last
  }
}

请注意切换到NewThreadScheduler并使用scheduleRec方法,而不是手动递归调度。

感谢您的输入。今天晚上我还要玩一些。