我想要实现的是实现类似于带有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
的能力,所以我真的必须知道,是否流推下一个或没有从下游请求下一个
我也玩过conflate
和expand
,但是这些我们对结果的位置偏移情况更糟糕
我在配置中更改的一件事是流量的initial
和max
缓冲区,因此我可以确定指示的需求确实在我推送它的元素之后。
就如何解决这个问题提出一些建议会很好!
答案 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)]