与Akka Streams同步反馈

时间:2015-08-06 21:05:56

标签: scala akka-stream reactive-streams backpressure

我想要实现的是实现类似于带有akka流的同步反馈循环。

假设你有一个Flow[Int].filter(_ % 5 == 0)。当您向此流广播Int的流并将元组直接压缩在其后面时,您会得到类似

的内容
(0,0)
(5,1)
(10,2)

有没有办法发出Option[Int],表示在我推动下一个元素之后是否发出了一个元素?

(Some(0),0)
(None, 1)
(None, 2)
(None, 3)
(None, 4)
(Some(5), 5)
(None, 6)
...

我想在DetachedStage前面和后面实现我自己的Flow以保持一个状态,每当流动在舞台上,我知道他需要下一个元素。当后面的阶段没有收到元素时,它是无。

不幸的是,许多职位的结果并不好。

旁注

过滤器Flow只是一个例子,它可能是一个非常长的流程,我无法在其中的每个阶段提供Option的能力,所以我真的必须知道,是否流推下一个或没有从下游请求下一个

我也玩过conflateexpand,但是这些我们对结果的位置偏移情况更糟糕

我在配置中更改的一件事是流量的initialmax缓冲区,因此我可以确定指示的需求确实在我推送它的元素之后。

就如何解决这个问题提出一些建议会很好!

1 个答案:

答案 0 :(得分:2)

我无法准确地生产你想要的东西。但我可以找到你正在寻找的 Future ,例如:

(Future(Some(0)), 0)
(Future(None)   , 1)
(Future(None)   , 2)
...

扩展您的示例,如果给出了无法更改的流程:

val flow = Flow[Int].filter(_ % 5 == 0)

然后可以在单个输入上评估此流程,并将结果转换为Option

import scala.concurrent.{Future, Promise}
import akka.stream.{Materializer, ActorMaterializer}
import akka.stream.scaladsl.{Source,Sink}

def evalFlow(in : Int, flow : Flow[Int, Int, _])(implicit mat : Materializer, ec : ExecutionContext) = {
  val fut : Future[Int] = 
    Source.single(in)
          .via(flow)
          .runWith(Sink.head) //Throws an Exception if filter fails

  fut.map(Some(_))              //       val => Some(val)
     .fallbackTo(Promise(None)) // Exception => None
} 

此函数返回Future[Option[Int]]。然后我们可以使用评估简单地将结果与输入结合起来:

def evalAndCombine(flow : Flow[Int, Int, _])(in : Int)(implicit mat : Materializer, ec : ExecutionContext) =
  (evalFlow(in, flow), in)//(Future[Option[Int]], Int)

最后,evalAndCombine函数可以放在你的来源之后:

import akka.actor.ActorSystem

implicit val actorSystem = ActorSystem()
implicit val mat = ActorMaterializer()
import actorSystem.dispatcher

val exampleSource = Source(() => (1 to 6).toIterator)

val tupleSource = exampleSource map evalAndCombine(flow)

同样,如果您想要Future[(Option[Int], Int)]而不是(Future[Option[Int]], Int),例如:

Future[(Some(0), 0)]
Future[(None   , 1)]
...

然后稍微修改组合功能:

def evalAndCombine(flow : Flow[Int, Int, _])(in : Int)(implicit mat : Materializer, ec : ExecutionContext) =
  evalFlow(in, flow) map (option => (option, in))//Future[(Option[Int], Int)]