当_any_的子流准备好值时合并流

时间:2017-01-28 10:24:10

标签: akka-stream low-latency

从Akka-stream文档中看,所有流合并选项(merge,mergeSorted,mergePreferred,zipN,zipWithN)通过等待所有合并流都准备好新元素,然后应用合并策略(将元素组合到一个元组,或应用拉链功能等。)

这适用于离线处理(例如,从文件或HTTP中读取数据并将其组合),但它会引入在线处理的延迟。我需要合并由例如数据流生成的数据流。多个Websocket连接,并在任何源流生成值时立即在合并流中提供更新。示例:如果有源流A和B,这里应该是合并流中的内容:

输出流以一些初始值开始,例如(None, None)

(A:1) (B:<not ready>) -> (Some(1), None)
(A:2) (B:<not ready>) -> (Some(2), None)
(A:3) (B:1)           -> (Some(3), Some(1))
(A:3) (B:2)           -> (Some(3), Some(2))

等。同样,当源流的任何立即产生值时,输出流中会出现一个新值。

是否有任何组合来实现这一目标?

1 个答案:

答案 0 :(得分:3)

正如评论中所述,MergeMergePreferred阶段确实向下游发射元素,即使并非所有上游都有可用元素。

从你的例子看,你看起来正在寻找压缩源。是的,Zip仅在具有从其所有上游压缩的元素时才向下游发出压缩元组。为了克服这个问题,你可以解除这个问题。您的源生成Option s,并在没有其他任何内容发出时让它们发出None。源包装器可能如下所示:

  def asOption[In, Mat](source: Source[In, Mat]): Source[Option[In], Mat] =
    Source.fromGraph(GraphDSL.create(source.map(Option(_))) {
      implicit builder: GraphDSL.Builder[Mat] => src =>
      import GraphDSL.Implicits._

      val noneSource = Source.repeat(None)
      val merge = builder.add(MergePreferred[Option[In]](1))

      src        ~> merge.preferred
      noneSource ~> merge.in(0)

      SourceShape(merge.out)
    })

此时您可以像往常一样压缩您的来源。

  val src1: Source[Int, NotUsed] = ???
  val src2: Source[Int, NotUsed] = ???

  val zipped = asOption(src1) zip asOption(src2)