Scala Akka反应流始终落后于一条消息

Scala Akka反应流始终落后于一条消息,scala,akka,akka-stream,reactive-streams,Scala,Akka,Akka Stream,Reactive Streams,出于某种原因,我的Akka流总是在“发出”(?)第一条消息之前等待第二条消息 下面是一些演示我的问题的示例代码 val rx = Source((1 to 100).toStream.map { t => Thread.sleep(1000) println(s"doing $t") t }) rx.runForeach(println) 产量: doing 1 doing 2 1 doing 3 2 doing 4 3 doing 5 4 doing 6 5 ... 我想

出于某种原因,我的Akka流总是在“发出”(?)第一条消息之前等待第二条消息

下面是一些演示我的问题的示例代码

val rx = Source((1 to 100).toStream.map { t =>
  Thread.sleep(1000)
  println(s"doing $t")
  t
})
rx.runForeach(println)
产量:

doing 1
doing 2
1
doing 3
2
doing 4
3
doing 5
4
doing 6
5
...
我想要的是:

doing 1
1
doing 2
2
doing 3
3
doing 4
4
doing 5
5
doing 6
6
...

您正在使用
.toStream()
,这意味着整个集合都是惰性的。如果没有它,您的输出将是第一个一百个“正在做”的,然后是从1到100的数字。但是,
Stream
只计算第一个元素,该元素给出“doing 1”输出,即它停止的位置。下一个元素将在需要时进行评估

现在,我在文档中找不到关于这方面的任何详细信息,但我假设
runForeach
有一个实现,它在调用当前元素上的函数之前接受下一个元素。因此,在对元素n调用
println
之前,它首先检查元素n+1(例如,检查它是否存在),这将导致“doing n+1”消息。然后它对当前元素执行
println
函数,结果显示消息“n”

在运行
runForeach
之前,您真的需要
map()
?我的意思是,你需要两次数据旅行吗?我知道我可能是在说显而易见的事情,但如果您只需像这样一次性处理数据:

val rx = Source((1 to 100).toStream)
rx.runForeach({ t =>
  Thread.sleep(1000)
  println(s"doing $t")
  // do something with 't', which is now equal to what "doing" says
})
val transform =
  Flow[Int].map{ t =>
    Thread.sleep(1000)
    println(s"doing $t")
    t
  }

Source((1 to 100).toStream).
  via(transform ).
  to(Sink.foreach(println)).
  run

这样,您就不会有什么时候计算的问题。

现在设置代码的方式是,在允许开始向下游发射元素之前,您正在完全转换
源代码。通过删除表示源的数字范围上的
toStream
,您可以清楚地看到该行为(如@slouc所述)。如果您这样做,您将看到
源代码在开始响应下游需求之前首先被完全转换。如果你真的想把<代码>源码<代码>运行到<代码>下沉>代码中,并在中间有一个转换步骤,那么你可以尝试和构造这样的事情:

val rx = Source((1 to 100).toStream)
rx.runForeach({ t =>
  Thread.sleep(1000)
  println(s"doing $t")
  // do something with 't', which is now equal to what "doing" says
})
val transform =
  Flow[Int].map{ t =>
    Thread.sleep(1000)
    println(s"doing $t")
    t
  }

Source((1 to 100).toStream).
  via(transform ).
  to(Sink.foreach(println)).
  run

如果您进行了更改,那么您将获得所需的效果,即在开始处理下一个元素之前,一个向下游流动的元素将在整个流程中得到处理。

我在发布它时实际上简化了问题。流来自Java BufferedReader(我从套接字获得)<代码>源代码(Stream.continuously(myBufferedReader.readLine).map(t=>(System.nanoTime,t))
我这样做最初是为了尝试在消息实际到达我的机器时以及在它们最终被处理时“加时间戳”。不过,谢谢你的回答。我现在更清楚了!我以为我可以简化我的问题并解决它,但我认为我把它简化了。你的回答确实解决了我发布的问题,但我可能不得不提出一个更详细的新问题。也许你看到了。